/[jscoverage]/trunk/js/jsobj.cpp
ViewVC logotype

Annotation of /trunk/js/jsobj.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 585 - (hide annotations)
Sun Sep 12 15:13:23 2010 UTC (9 years, 1 month ago) by siliconforks
File size: 196889 byte(s)
Update to SpiderMonkey from Firefox 3.6.9.

1 siliconforks 507 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 siliconforks 460 * vim: set ts=8 sw=4 et tw=79:
3 siliconforks 332 *
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 Mozilla Communicator client code, released
18     * March 31, 1998.
19     *
20     * The Initial Developer of the Original Code is
21     * Netscape Communications Corporation.
22     * Portions created by the Initial Developer are Copyright (C) 1998
23     * the Initial Developer. All Rights Reserved.
24     *
25     * Contributor(s):
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     /*
42     * JS object implementation.
43     */
44     #include <stdlib.h>
45     #include <string.h>
46     #include "jstypes.h"
47 siliconforks 507 #include "jsstdint.h"
48 siliconforks 332 #include "jsarena.h" /* Added by JSIFY */
49     #include "jsbit.h"
50     #include "jsutil.h" /* Added by JSIFY */
51     #include "jshash.h" /* Added by JSIFY */
52     #include "jsdhash.h"
53     #include "jsprf.h"
54     #include "jsapi.h"
55     #include "jsarray.h"
56     #include "jsatom.h"
57     #include "jsbool.h"
58 siliconforks 399 #include "jsbuiltins.h"
59 siliconforks 332 #include "jscntxt.h"
60     #include "jsversion.h"
61     #include "jsemit.h"
62     #include "jsfun.h"
63     #include "jsgc.h"
64     #include "jsinterp.h"
65     #include "jslock.h"
66     #include "jsnum.h"
67     #include "jsobj.h"
68     #include "jsopcode.h"
69     #include "jsparse.h"
70     #include "jsscope.h"
71     #include "jsscript.h"
72 siliconforks 507 #include "jsscriptinlines.h"
73 siliconforks 460 #include "jsstaticcheck.h"
74 siliconforks 332 #include "jsstr.h"
75 siliconforks 460 #include "jstracer.h"
76     #include "jsdbgapi.h"
77 siliconforks 332
78     #if JS_HAS_GENERATORS
79     #include "jsiter.h"
80     #endif
81    
82     #if JS_HAS_XML_SUPPORT
83     #include "jsxml.h"
84     #endif
85    
86     #if JS_HAS_XDR
87     #include "jsxdrapi.h"
88     #endif
89    
90     #ifdef INCLUDE_MOZILLA_DTRACE
91     #include "jsdtracef.h"
92     #endif
93    
94 siliconforks 507 #include "jsatominlines.h"
95     #include "jsobjinlines.h"
96     #include "jsscriptinlines.h"
97    
98 siliconforks 332 #include "jsautooplen.h"
99    
100     #ifdef JS_THREADSAFE
101     #define NATIVE_DROP_PROPERTY js_DropProperty
102    
103     extern void
104     js_DropProperty(JSContext *cx, JSObject *obj, JSProperty *prop);
105     #else
106     #define NATIVE_DROP_PROPERTY NULL
107     #endif
108    
109     JS_FRIEND_DATA(JSObjectOps) js_ObjectOps = {
110 siliconforks 460 NULL,
111 siliconforks 332 js_LookupProperty, js_DefineProperty,
112     js_GetProperty, js_SetProperty,
113     js_GetAttributes, js_SetAttributes,
114     js_DeleteProperty, js_DefaultValue,
115     js_Enumerate, js_CheckAccess,
116     NULL, NATIVE_DROP_PROPERTY,
117     js_Call, js_Construct,
118 siliconforks 460 js_HasInstance, js_TraceObject,
119 siliconforks 507 js_Clear
120 siliconforks 332 };
121    
122     JSClass js_ObjectClass = {
123     js_Object_str,
124     JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
125     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
126 siliconforks 507 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL,
127 siliconforks 332 JSCLASS_NO_OPTIONAL_MEMBERS
128     };
129    
130     #if JS_HAS_OBJ_PROTO_PROP
131    
132     static JSBool
133     obj_getSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
134    
135     static JSBool
136     obj_setSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
137    
138     static JSBool
139     obj_getCount(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
140    
141     static JSPropertySpec object_props[] = {
142     /* These two must come first; see object_props[slot].name usage below. */
143     {js_proto_str, JSSLOT_PROTO, JSPROP_PERMANENT|JSPROP_SHARED,
144     obj_getSlot, obj_setSlot},
145     {js_parent_str,JSSLOT_PARENT,JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED,
146     obj_getSlot, obj_setSlot},
147     {js_count_str, 0, JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED,
148     obj_getCount, NULL},
149     {0,0,0,0,0}
150     };
151    
152     /* NB: JSSLOT_PROTO and JSSLOT_PARENT are already indexes into object_props. */
153     #define JSSLOT_COUNT 2
154    
155     static JSBool
156     ReportStrictSlot(JSContext *cx, uint32 slot)
157     {
158     if (slot == JSSLOT_PROTO)
159     return JS_TRUE;
160     return JS_ReportErrorFlagsAndNumber(cx,
161     JSREPORT_WARNING | JSREPORT_STRICT,
162     js_GetErrorMessage, NULL,
163     JSMSG_DEPRECATED_USAGE,
164     object_props[slot].name);
165     }
166    
167     static JSBool
168     obj_getSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
169     {
170     uint32 slot;
171     jsid propid;
172     JSAccessMode mode;
173     uintN attrs;
174     JSObject *pobj;
175     JSClass *clasp;
176    
177     slot = (uint32) JSVAL_TO_INT(id);
178     if (id == INT_TO_JSVAL(JSSLOT_PROTO)) {
179     propid = ATOM_TO_JSID(cx->runtime->atomState.protoAtom);
180     mode = JSACC_PROTO;
181     } else {
182     propid = ATOM_TO_JSID(cx->runtime->atomState.parentAtom);
183     mode = JSACC_PARENT;
184     }
185    
186 siliconforks 507 /* Let obj->checkAccess get the slot's value, based on the access mode. */
187     if (!obj->checkAccess(cx, propid, mode, vp, &attrs))
188 siliconforks 332 return JS_FALSE;
189    
190     pobj = JSVAL_TO_OBJECT(*vp);
191     if (pobj) {
192     clasp = OBJ_GET_CLASS(cx, pobj);
193     if (clasp == &js_CallClass || clasp == &js_BlockClass) {
194     /* Censor activations and lexical scopes per ECMA-262. */
195     *vp = JSVAL_NULL;
196 siliconforks 460 } else {
197     /*
198     * DeclEnv only exists as a parent for a Call object which we
199     * censor. So it cannot escape to scripts.
200     */
201     JS_ASSERT(clasp != &js_DeclEnvClass);
202     if (pobj->map->ops->thisObject) {
203     pobj = pobj->map->ops->thisObject(cx, pobj);
204 siliconforks 332 if (!pobj)
205     return JS_FALSE;
206     *vp = OBJECT_TO_JSVAL(pobj);
207     }
208     }
209     }
210     return JS_TRUE;
211     }
212    
213     static JSBool
214     obj_setSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
215     {
216     JSObject *pobj;
217     uint32 slot;
218     jsid propid;
219     uintN attrs;
220    
221     if (!JSVAL_IS_OBJECT(*vp))
222     return JS_TRUE;
223     pobj = JSVAL_TO_OBJECT(*vp);
224    
225     if (pobj) {
226     /*
227     * Innerize pobj here to avoid sticking unwanted properties on the
228     * outer object. This ensures that any with statements only grant
229     * access to the inner object.
230     */
231     OBJ_TO_INNER_OBJECT(cx, pobj);
232     if (!pobj)
233     return JS_FALSE;
234     }
235     slot = (uint32) JSVAL_TO_INT(id);
236     if (JS_HAS_STRICT_OPTION(cx) && !ReportStrictSlot(cx, slot))
237     return JS_FALSE;
238    
239     /* __parent__ is readonly and permanent, only __proto__ may be set. */
240     propid = ATOM_TO_JSID(cx->runtime->atomState.protoAtom);
241 siliconforks 507 if (!obj->checkAccess(cx, propid, (JSAccessMode)(JSACC_PROTO|JSACC_WRITE), vp, &attrs))
242 siliconforks 332 return JS_FALSE;
243    
244 siliconforks 460 return js_SetProtoOrParent(cx, obj, slot, pobj, JS_TRUE);
245 siliconforks 332 }
246    
247     static JSBool
248     obj_getCount(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
249     {
250     jsval iter_state;
251     jsid num_properties;
252     JSBool ok;
253    
254     if (JS_HAS_STRICT_OPTION(cx) && !ReportStrictSlot(cx, JSSLOT_COUNT))
255     return JS_FALSE;
256    
257 siliconforks 507 iter_state = JSVAL_NULL;
258     JSAutoEnumStateRooter tvr(cx, obj, &iter_state);
259    
260 siliconforks 332 /* Get the number of properties to enumerate. */
261 siliconforks 507 ok = obj->enumerate(cx, JSENUMERATE_INIT, &iter_state, &num_properties);
262 siliconforks 332 if (!ok)
263     goto out;
264    
265     if (!JSVAL_IS_INT(num_properties)) {
266     JS_ASSERT(0);
267     *vp = JSVAL_ZERO;
268     goto out;
269     }
270     *vp = num_properties;
271    
272     out:
273 siliconforks 507 if (!JSVAL_IS_NULL(iter_state))
274     ok &= obj->enumerate(cx, JSENUMERATE_DESTROY, &iter_state, 0);
275 siliconforks 332 return ok;
276     }
277    
278     #else /* !JS_HAS_OBJ_PROTO_PROP */
279    
280     #define object_props NULL
281    
282     #endif /* !JS_HAS_OBJ_PROTO_PROP */
283    
284     JSBool
285 siliconforks 460 js_SetProtoOrParent(JSContext *cx, JSObject *obj, uint32 slot, JSObject *pobj,
286     JSBool checkForCycles)
287 siliconforks 332 {
288 siliconforks 460 JS_ASSERT(slot == JSSLOT_PARENT || slot == JSSLOT_PROTO);
289     JS_ASSERT_IF(!checkForCycles, obj != pobj);
290 siliconforks 332
291 siliconforks 460 if (slot == JSSLOT_PROTO) {
292     if (OBJ_IS_NATIVE(obj)) {
293     JS_LOCK_OBJ(cx, obj);
294     bool ok = !!js_GetMutableScope(cx, obj);
295 siliconforks 332 JS_UNLOCK_OBJ(cx, obj);
296 siliconforks 460 if (!ok)
297     return JS_FALSE;
298 siliconforks 332 }
299 siliconforks 460
300     /*
301     * Regenerate property cache shape ids for all of the scopes along the
302     * old prototype chain to invalidate their property cache entries, in
303 siliconforks 507 * case any entries were filled by looking up through obj.
304 siliconforks 460 */
305     JSObject *oldproto = obj;
306     while (oldproto && OBJ_IS_NATIVE(oldproto)) {
307     JS_LOCK_OBJ(cx, oldproto);
308     JSScope *scope = OBJ_SCOPE(oldproto);
309 siliconforks 507 scope->protoShapeChange(cx);
310     JSObject *tmp = STOBJ_GET_PROTO(oldproto);
311 siliconforks 460 JS_UNLOCK_OBJ(cx, oldproto);
312     oldproto = tmp;
313     }
314 siliconforks 332 }
315    
316 siliconforks 460 if (!pobj || !checkForCycles) {
317     if (slot == JSSLOT_PROTO)
318 siliconforks 507 obj->setProto(pobj);
319 siliconforks 460 else
320 siliconforks 507 obj->setParent(pobj);
321 siliconforks 460 } else {
322     /*
323     * Use the GC machinery to serialize access to all objects on the
324     * prototype or parent chain.
325     */
326     JSSetSlotRequest ssr;
327     ssr.obj = obj;
328     ssr.pobj = pobj;
329     ssr.slot = (uint16) slot;
330     ssr.cycle = false;
331 siliconforks 332
332 siliconforks 460 JSRuntime *rt = cx->runtime;
333 siliconforks 332 JS_LOCK_GC(rt);
334 siliconforks 460 ssr.next = rt->setSlotRequests;
335     rt->setSlotRequests = &ssr;
336     for (;;) {
337     js_GC(cx, GC_SET_SLOT_REQUEST);
338     JS_UNLOCK_GC(rt);
339     if (!rt->setSlotRequests)
340     break;
341     JS_LOCK_GC(rt);
342     }
343 siliconforks 332
344 siliconforks 460 if (ssr.cycle) {
345     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
346     JSMSG_CYCLIC_VALUE,
347 siliconforks 332 #if JS_HAS_OBJ_PROTO_PROP
348     object_props[slot].name
349     #else
350     (slot == JSSLOT_PROTO) ? js_proto_str
351     : js_parent_str
352     #endif
353     );
354 siliconforks 460 return JS_FALSE;
355 siliconforks 332 }
356     }
357     return JS_TRUE;
358     }
359    
360     static JSHashNumber
361     js_hash_object(const void *key)
362     {
363     return (JSHashNumber)JS_PTR_TO_UINT32(key) >> JSVAL_TAGBITS;
364     }
365    
366     static JSHashEntry *
367     MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap)
368     {
369     JSSharpObjectMap *map;
370     JSHashTable *table;
371     JSHashNumber hash;
372     JSHashEntry **hep, *he;
373     jsatomid sharpid;
374     JSIdArray *ida;
375     JSBool ok;
376     jsint i, length;
377     jsid id;
378     #if JS_HAS_GETTER_SETTER
379     JSObject *obj2;
380     JSProperty *prop;
381     uintN attrs;
382     #endif
383     jsval val;
384    
385     JS_CHECK_RECURSION(cx, return NULL);
386    
387     map = &cx->sharpObjectMap;
388 siliconforks 460 JS_ASSERT(map->depth >= 1);
389 siliconforks 332 table = map->table;
390     hash = js_hash_object(obj);
391     hep = JS_HashTableRawLookup(table, hash, obj);
392     he = *hep;
393     if (!he) {
394     sharpid = 0;
395     he = JS_HashTableRawAdd(table, hep, hash, obj,
396     JS_UINT32_TO_PTR(sharpid));
397     if (!he) {
398     JS_ReportOutOfMemory(cx);
399     return NULL;
400     }
401    
402     ida = JS_Enumerate(cx, obj);
403     if (!ida)
404     return NULL;
405    
406     ok = JS_TRUE;
407     for (i = 0, length = ida->length; i < length; i++) {
408     id = ida->vector[i];
409     #if JS_HAS_GETTER_SETTER
410 siliconforks 507 ok = obj->lookupProperty(cx, id, &obj2, &prop);
411 siliconforks 332 if (!ok)
412     break;
413     if (!prop)
414     continue;
415 siliconforks 507 ok = obj2->getAttributes(cx, id, prop, &attrs);
416 siliconforks 332 if (ok) {
417     if (OBJ_IS_NATIVE(obj2) &&
418     (attrs & (JSPROP_GETTER | JSPROP_SETTER))) {
419 siliconforks 460 JSScopeProperty *sprop = (JSScopeProperty *) prop;
420 siliconforks 332 val = JSVAL_NULL;
421     if (attrs & JSPROP_GETTER)
422 siliconforks 460 val = js_CastAsObjectJSVal(sprop->getter);
423 siliconforks 332 if (attrs & JSPROP_SETTER) {
424     if (val != JSVAL_NULL) {
425     /* Mark the getter, then set val to setter. */
426     ok = (MarkSharpObjects(cx, JSVAL_TO_OBJECT(val),
427     NULL)
428     != NULL);
429     }
430 siliconforks 460 val = js_CastAsObjectJSVal(sprop->setter);
431 siliconforks 332 }
432     } else {
433 siliconforks 507 ok = obj->getProperty(cx, id, &val);
434 siliconforks 332 }
435     }
436 siliconforks 507 obj2->dropProperty(cx, prop);
437 siliconforks 332 #else
438 siliconforks 507 ok = obj->getProperty(cx, id, &val);
439 siliconforks 332 #endif
440     if (!ok)
441     break;
442     if (!JSVAL_IS_PRIMITIVE(val) &&
443     !MarkSharpObjects(cx, JSVAL_TO_OBJECT(val), NULL)) {
444     ok = JS_FALSE;
445     break;
446     }
447     }
448     if (!ok || !idap)
449     JS_DestroyIdArray(cx, ida);
450     if (!ok)
451     return NULL;
452     } else {
453     sharpid = JS_PTR_TO_UINT32(he->value);
454     if (sharpid == 0) {
455     sharpid = ++map->sharpgen << SHARP_ID_SHIFT;
456     he->value = JS_UINT32_TO_PTR(sharpid);
457     }
458     ida = NULL;
459     }
460     if (idap)
461     *idap = ida;
462     return he;
463     }
464    
465     JSHashEntry *
466     js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap,
467     jschar **sp)
468     {
469     JSSharpObjectMap *map;
470     JSHashTable *table;
471     JSIdArray *ida;
472     JSHashNumber hash;
473     JSHashEntry *he, **hep;
474     jsatomid sharpid;
475     char buf[20];
476     size_t len;
477    
478 siliconforks 460 if (!JS_CHECK_OPERATION_LIMIT(cx))
479 siliconforks 332 return NULL;
480    
481     /* Set to null in case we return an early error. */
482     *sp = NULL;
483     map = &cx->sharpObjectMap;
484     table = map->table;
485     if (!table) {
486     table = JS_NewHashTable(8, js_hash_object, JS_CompareValues,
487     JS_CompareValues, NULL, NULL);
488     if (!table) {
489     JS_ReportOutOfMemory(cx);
490     return NULL;
491     }
492     map->table = table;
493     JS_KEEP_ATOMS(cx->runtime);
494     }
495    
496     /* From this point the control must flow either through out: or bad:. */
497     ida = NULL;
498     if (map->depth == 0) {
499 siliconforks 460 /*
500     * Although MarkSharpObjects tries to avoid invoking getters,
501     * it ends up doing so anyway under some circumstances; for
502     * example, if a wrapped object has getters, the wrapper will
503     * prevent MarkSharpObjects from recognizing them as such.
504     * This could lead to js_LeaveSharpObject being called while
505     * MarkSharpObjects is still working.
506     *
507     * Increment map->depth while we call MarkSharpObjects, to
508     * ensure that such a call doesn't free the hash table we're
509     * still using.
510     */
511     ++map->depth;
512 siliconforks 332 he = MarkSharpObjects(cx, obj, &ida);
513 siliconforks 460 --map->depth;
514 siliconforks 332 if (!he)
515     goto bad;
516     JS_ASSERT((JS_PTR_TO_UINT32(he->value) & SHARP_BIT) == 0);
517     if (!idap) {
518     JS_DestroyIdArray(cx, ida);
519     ida = NULL;
520     }
521     } else {
522     hash = js_hash_object(obj);
523     hep = JS_HashTableRawLookup(table, hash, obj);
524     he = *hep;
525    
526     /*
527     * It's possible that the value of a property has changed from the
528     * first time the object's properties are traversed (when the property
529     * ids are entered into the hash table) to the second (when they are
530 siliconforks 507 * converted to strings), i.e., the JSObject::getProperty() call is not
531 siliconforks 332 * idempotent.
532     */
533     if (!he) {
534     he = JS_HashTableRawAdd(table, hep, hash, obj, NULL);
535     if (!he) {
536     JS_ReportOutOfMemory(cx);
537     goto bad;
538     }
539     sharpid = 0;
540     goto out;
541     }
542     }
543    
544     sharpid = JS_PTR_TO_UINT32(he->value);
545     if (sharpid != 0) {
546     len = JS_snprintf(buf, sizeof buf, "#%u%c",
547     sharpid >> SHARP_ID_SHIFT,
548     (sharpid & SHARP_BIT) ? '#' : '=');
549     *sp = js_InflateString(cx, buf, &len);
550     if (!*sp) {
551     if (ida)
552     JS_DestroyIdArray(cx, ida);
553     goto bad;
554     }
555     }
556    
557     out:
558     JS_ASSERT(he);
559     if ((sharpid & SHARP_BIT) == 0) {
560     if (idap && !ida) {
561     ida = JS_Enumerate(cx, obj);
562     if (!ida) {
563     if (*sp) {
564 siliconforks 507 cx->free(*sp);
565 siliconforks 332 *sp = NULL;
566     }
567     goto bad;
568     }
569     }
570     map->depth++;
571     }
572    
573     if (idap)
574     *idap = ida;
575     return he;
576    
577     bad:
578     /* Clean up the sharpObjectMap table on outermost error. */
579     if (map->depth == 0) {
580     JS_UNKEEP_ATOMS(cx->runtime);
581     map->sharpgen = 0;
582     JS_HashTableDestroy(map->table);
583     map->table = NULL;
584     }
585     return NULL;
586     }
587    
588     void
589     js_LeaveSharpObject(JSContext *cx, JSIdArray **idap)
590     {
591     JSSharpObjectMap *map;
592     JSIdArray *ida;
593    
594     map = &cx->sharpObjectMap;
595     JS_ASSERT(map->depth > 0);
596     if (--map->depth == 0) {
597     JS_UNKEEP_ATOMS(cx->runtime);
598     map->sharpgen = 0;
599     JS_HashTableDestroy(map->table);
600     map->table = NULL;
601     }
602     if (idap) {
603     ida = *idap;
604     if (ida) {
605     JS_DestroyIdArray(cx, ida);
606     *idap = NULL;
607     }
608     }
609     }
610    
611     static intN
612     gc_sharp_table_entry_marker(JSHashEntry *he, intN i, void *arg)
613     {
614     JS_CALL_OBJECT_TRACER((JSTracer *)arg, (JSObject *)he->key,
615     "sharp table entry");
616     return JS_DHASH_NEXT;
617     }
618    
619     void
620     js_TraceSharpMap(JSTracer *trc, JSSharpObjectMap *map)
621     {
622     JS_ASSERT(map->depth > 0);
623     JS_ASSERT(map->table);
624    
625     /*
626     * During recursive calls to MarkSharpObjects a non-native object or
627     * object with a custom getProperty method can potentially return an
628     * unrooted value or even cut from the object graph an argument of one of
629     * MarkSharpObjects recursive invocations. So we must protect map->table
630     * entries against GC.
631     *
632     * We can not simply use JSTempValueRooter to mark the obj argument of
633     * MarkSharpObjects during recursion as we have to protect *all* entries
634     * in JSSharpObjectMap including those that contains otherwise unreachable
635     * objects just allocated through custom getProperty. Otherwise newer
636     * allocations can re-use the address of an object stored in the hashtable
637     * confusing js_EnterSharpObject. So to address the problem we simply
638     * mark all objects from map->table.
639     *
640     * An alternative "proper" solution is to use JSTempValueRooter in
641     * MarkSharpObjects with code to remove during finalization entries
642     * with otherwise unreachable objects. But this is way too complex
643     * to justify spending efforts.
644     */
645     JS_HashTableEnumerateEntries(map->table, gc_sharp_table_entry_marker, trc);
646     }
647    
648     #if JS_HAS_TOSOURCE
649     static JSBool
650     obj_toSource(JSContext *cx, uintN argc, jsval *vp)
651     {
652     JSBool ok, outermost;
653     JSObject *obj;
654     JSHashEntry *he;
655     JSIdArray *ida;
656     jschar *chars, *ochars, *vsharp;
657     const jschar *idstrchars, *vchars;
658     size_t nchars, idstrlength, gsoplength, vlength, vsharplength, curlen;
659     const char *comma;
660     jsint i, j, length, valcnt;
661     jsid id;
662     #if JS_HAS_GETTER_SETTER
663     JSObject *obj2;
664     JSProperty *prop;
665     uintN attrs;
666     #endif
667     jsval *val;
668     jsval localroot[4] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL, JSVAL_NULL};
669     JSTempValueRooter tvr;
670     JSString *gsopold[2];
671     JSString *gsop[2];
672     JSString *idstr, *valstr, *str;
673    
674     JS_CHECK_RECURSION(cx, return JS_FALSE);
675    
676     MUST_FLOW_THROUGH("out");
677     JS_PUSH_TEMP_ROOT(cx, 4, localroot, &tvr);
678    
679     /* If outermost, we need parentheses to be an expression, not a block. */
680     outermost = (cx->sharpObjectMap.depth == 0);
681     obj = JS_THIS_OBJECT(cx, vp);
682     if (!obj || !(he = js_EnterSharpObject(cx, obj, &ida, &chars))) {
683     ok = JS_FALSE;
684     goto out;
685     }
686     if (IS_SHARP(he)) {
687     /*
688     * We didn't enter -- obj is already "sharp", meaning we've visited it
689     * already in our depth first search, and therefore chars contains a
690     * string of the form "#n#".
691     */
692     JS_ASSERT(!ida);
693     #if JS_HAS_SHARP_VARS
694     nchars = js_strlen(chars);
695     #else
696     chars[0] = '{';
697     chars[1] = '}';
698     chars[2] = 0;
699     nchars = 2;
700     #endif
701     goto make_string;
702     }
703     JS_ASSERT(ida);
704     ok = JS_TRUE;
705    
706     if (!chars) {
707     /* If outermost, allocate 4 + 1 for "({})" and the terminator. */
708 siliconforks 507 chars = (jschar *) js_malloc(((outermost ? 4 : 2) + 1) * sizeof(jschar));
709 siliconforks 332 nchars = 0;
710     if (!chars)
711     goto error;
712     if (outermost)
713     chars[nchars++] = '(';
714     } else {
715     /* js_EnterSharpObject returned a string of the form "#n=" in chars. */
716     MAKE_SHARP(he);
717     nchars = js_strlen(chars);
718     chars = (jschar *)
719 siliconforks 507 js_realloc((ochars = chars), (nchars + 2 + 1) * sizeof(jschar));
720 siliconforks 332 if (!chars) {
721 siliconforks 507 js_free(ochars);
722 siliconforks 332 goto error;
723     }
724     if (outermost) {
725     /*
726     * No need for parentheses around the whole shebang, because #n=
727     * unambiguously begins an object initializer, and never a block
728     * statement.
729     */
730     outermost = JS_FALSE;
731     }
732     }
733    
734     chars[nchars++] = '{';
735    
736     comma = NULL;
737    
738     /*
739     * We have four local roots for cooked and raw value GC safety. Hoist the
740     * "localroot + 2" out of the loop using the val local, which refers to
741     * the raw (unconverted, "uncooked") values.
742     */
743     val = localroot + 2;
744    
745     for (i = 0, length = ida->length; i < length; i++) {
746     JSBool idIsLexicalIdentifier, needOldStyleGetterSetter;
747    
748     /* Get strings for id and value and GC-root them via vp. */
749     id = ida->vector[i];
750    
751     #if JS_HAS_GETTER_SETTER
752 siliconforks 507 ok = obj->lookupProperty(cx, id, &obj2, &prop);
753 siliconforks 332 if (!ok)
754     goto error;
755     #endif
756    
757     /*
758     * Convert id to a jsval and then to a string. Decide early whether we
759     * prefer get/set or old getter/setter syntax.
760     */
761     idstr = js_ValueToString(cx, ID_TO_VALUE(id));
762     if (!idstr) {
763     ok = JS_FALSE;
764 siliconforks 507 obj2->dropProperty(cx, prop);
765 siliconforks 332 goto error;
766     }
767     *vp = STRING_TO_JSVAL(idstr); /* local root */
768     idIsLexicalIdentifier = js_IsIdentifier(idstr);
769     needOldStyleGetterSetter =
770     !idIsLexicalIdentifier ||
771 siliconforks 507 js_CheckKeyword(idstr->chars(), idstr->length()) != TOK_EOF;
772 siliconforks 332
773     #if JS_HAS_GETTER_SETTER
774    
775     valcnt = 0;
776     if (prop) {
777 siliconforks 507 ok = obj2->getAttributes(cx, id, prop, &attrs);
778 siliconforks 332 if (!ok) {
779 siliconforks 507 obj2->dropProperty(cx, prop);
780 siliconforks 332 goto error;
781     }
782     if (OBJ_IS_NATIVE(obj2) &&
783     (attrs & (JSPROP_GETTER | JSPROP_SETTER))) {
784 siliconforks 460 JSScopeProperty *sprop = (JSScopeProperty *) prop;
785 siliconforks 332 if (attrs & JSPROP_GETTER) {
786 siliconforks 460 val[valcnt] = js_CastAsObjectJSVal(sprop->getter);
787 siliconforks 332 gsopold[valcnt] =
788     ATOM_TO_STRING(cx->runtime->atomState.getterAtom);
789     gsop[valcnt] =
790     ATOM_TO_STRING(cx->runtime->atomState.getAtom);
791    
792     valcnt++;
793     }
794     if (attrs & JSPROP_SETTER) {
795 siliconforks 460 val[valcnt] = js_CastAsObjectJSVal(sprop->setter);
796 siliconforks 332 gsopold[valcnt] =
797     ATOM_TO_STRING(cx->runtime->atomState.setterAtom);
798     gsop[valcnt] =
799     ATOM_TO_STRING(cx->runtime->atomState.setAtom);
800    
801     valcnt++;
802     }
803     } else {
804     valcnt = 1;
805     gsop[0] = NULL;
806     gsopold[0] = NULL;
807 siliconforks 507 ok = obj->getProperty(cx, id, &val[0]);
808 siliconforks 332 }
809 siliconforks 507 obj2->dropProperty(cx, prop);
810 siliconforks 332 }
811    
812     #else /* !JS_HAS_GETTER_SETTER */
813    
814     /*
815     * We simplify the source code at the price of minor dead code bloat in
816     * the ECMA version (for testing only, see jsversion.h). The null
817     * default values in gsop[j] suffice to disable non-ECMA getter and
818     * setter code.
819     */
820     valcnt = 1;
821     gsop[0] = NULL;
822     gsopold[0] = NULL;
823 siliconforks 507 ok = obj->getProperty(cx, id, &val[0]);
824 siliconforks 332
825     #endif /* !JS_HAS_GETTER_SETTER */
826    
827     if (!ok)
828     goto error;
829    
830     /*
831     * If id is a string that's not an identifier, then it needs to be
832     * quoted. Also, negative integer ids must be quoted.
833     */
834     if (JSID_IS_ATOM(id)
835     ? !idIsLexicalIdentifier
836     : (!JSID_IS_INT(id) || JSID_TO_INT(id) < 0)) {
837     idstr = js_QuoteString(cx, idstr, (jschar)'\'');
838     if (!idstr) {
839     ok = JS_FALSE;
840     goto error;
841     }
842     *vp = STRING_TO_JSVAL(idstr); /* local root */
843     }
844 siliconforks 507 idstr->getCharsAndLength(idstrchars, idstrlength);
845 siliconforks 332
846     for (j = 0; j < valcnt; j++) {
847     /* Convert val[j] to its canonical source form. */
848     valstr = js_ValueToSource(cx, val[j]);
849     if (!valstr) {
850     ok = JS_FALSE;
851     goto error;
852     }
853     localroot[j] = STRING_TO_JSVAL(valstr); /* local root */
854 siliconforks 507 valstr->getCharsAndLength(vchars, vlength);
855 siliconforks 332
856     if (vchars[0] == '#')
857     needOldStyleGetterSetter = JS_TRUE;
858    
859     if (needOldStyleGetterSetter)
860     gsop[j] = gsopold[j];
861    
862     /* If val[j] is a non-sharp object, consider sharpening it. */
863     vsharp = NULL;
864     vsharplength = 0;
865     #if JS_HAS_SHARP_VARS
866     if (!JSVAL_IS_PRIMITIVE(val[j]) && vchars[0] != '#') {
867     he = js_EnterSharpObject(cx, JSVAL_TO_OBJECT(val[j]), NULL,
868     &vsharp);
869     if (!he) {
870     ok = JS_FALSE;
871     goto error;
872     }
873     if (IS_SHARP(he)) {
874     vchars = vsharp;
875     vlength = js_strlen(vchars);
876     needOldStyleGetterSetter = JS_TRUE;
877     gsop[j] = gsopold[j];
878     } else {
879     if (vsharp) {
880     vsharplength = js_strlen(vsharp);
881     MAKE_SHARP(he);
882     needOldStyleGetterSetter = JS_TRUE;
883     gsop[j] = gsopold[j];
884     }
885     js_LeaveSharpObject(cx, NULL);
886     }
887     }
888     #endif
889    
890     #ifndef OLD_GETTER_SETTER
891     /*
892     * Remove '(function ' from the beginning of valstr and ')' from the
893     * end so that we can put "get" in front of the function definition.
894     */
895     if (gsop[j] && VALUE_IS_FUNCTION(cx, val[j]) &&
896     !needOldStyleGetterSetter) {
897     JSFunction *fun = JS_ValueToFunction(cx, val[j]);
898     const jschar *start = vchars;
899     const jschar *end = vchars + vlength;
900    
901     uint8 parenChomp = 0;
902     if (vchars[0] == '(') {
903     vchars++;
904     parenChomp = 1;
905     }
906    
907     /*
908     * Try to jump "getter" or "setter" keywords, if we suspect
909     * they might appear here. This code can be confused by people
910     * defining Function.prototype.toString, so let's be cautious.
911     */
912     if (JSFUN_GETTER_TEST(fun->flags) ||
913     JSFUN_SETTER_TEST(fun->flags)) { /* skip "getter/setter" */
914     const jschar *tmp = js_strchr_limit(vchars, ' ', end);
915     if (tmp)
916     vchars = tmp + 1;
917     }
918    
919     /* Try to jump "function" keyword. */
920     if (vchars)
921     vchars = js_strchr_limit(vchars, ' ', end);
922    
923     if (vchars) {
924     if (*vchars == ' ')
925     vchars++;
926     vlength = end - vchars - parenChomp;
927     } else {
928     gsop[j] = NULL;
929     vchars = start;
930     }
931     }
932     #else
933     needOldStyleGetterSetter = JS_TRUE;
934     gsop[j] = gsopold[j];
935     #endif
936    
937     #define SAFE_ADD(n) \
938     JS_BEGIN_MACRO \
939     size_t n_ = (n); \
940     curlen += n_; \
941     if (curlen < n_) \
942     goto overflow; \
943     JS_END_MACRO
944    
945     curlen = nchars;
946     if (comma)
947     SAFE_ADD(2);
948     SAFE_ADD(idstrlength + 1);
949     if (gsop[j])
950 siliconforks 507 SAFE_ADD(gsop[j]->length() + 1);
951 siliconforks 332 SAFE_ADD(vsharplength);
952     SAFE_ADD(vlength);
953     /* Account for the trailing null. */
954     SAFE_ADD((outermost ? 2 : 1) + 1);
955     #undef SAFE_ADD
956    
957     if (curlen > (size_t)-1 / sizeof(jschar))
958     goto overflow;
959    
960     /* Allocate 1 + 1 at end for closing brace and terminating 0. */
961     chars = (jschar *)
962 siliconforks 507 js_realloc((ochars = chars), curlen * sizeof(jschar));
963 siliconforks 332 if (!chars) {
964     /* Save code space on error: let JS_free ignore null vsharp. */
965 siliconforks 507 cx->free(vsharp);
966     js_free(ochars);
967 siliconforks 332 goto error;
968     }
969    
970     if (comma) {
971     chars[nchars++] = comma[0];
972     chars[nchars++] = comma[1];
973     }
974     comma = ", ";
975    
976     if (needOldStyleGetterSetter) {
977     js_strncpy(&chars[nchars], idstrchars, idstrlength);
978     nchars += idstrlength;
979     if (gsop[j]) {
980     chars[nchars++] = ' ';
981 siliconforks 507 gsoplength = gsop[j]->length();
982     js_strncpy(&chars[nchars], gsop[j]->chars(),
983 siliconforks 332 gsoplength);
984     nchars += gsoplength;
985     }
986     chars[nchars++] = ':';
987     } else { /* New style "decompilation" */
988     if (gsop[j]) {
989 siliconforks 507 gsoplength = gsop[j]->length();
990     js_strncpy(&chars[nchars], gsop[j]->chars(),
991 siliconforks 332 gsoplength);
992     nchars += gsoplength;
993     chars[nchars++] = ' ';
994     }
995     js_strncpy(&chars[nchars], idstrchars, idstrlength);
996     nchars += idstrlength;
997     /* Extraneous space after id here will be extracted later */
998     chars[nchars++] = gsop[j] ? ' ' : ':';
999     }
1000    
1001     if (vsharplength) {
1002     js_strncpy(&chars[nchars], vsharp, vsharplength);
1003     nchars += vsharplength;
1004     }
1005     js_strncpy(&chars[nchars], vchars, vlength);
1006     nchars += vlength;
1007    
1008     if (vsharp)
1009 siliconforks 507 cx->free(vsharp);
1010 siliconforks 332 }
1011     }
1012    
1013     chars[nchars++] = '}';
1014     if (outermost)
1015     chars[nchars++] = ')';
1016     chars[nchars] = 0;
1017    
1018     error:
1019     js_LeaveSharpObject(cx, &ida);
1020    
1021     if (!ok) {
1022     if (chars)
1023 siliconforks 507 js_free(chars);
1024 siliconforks 332 goto out;
1025     }
1026    
1027     if (!chars) {
1028     JS_ReportOutOfMemory(cx);
1029     ok = JS_FALSE;
1030     goto out;
1031     }
1032     make_string:
1033     str = js_NewString(cx, chars, nchars);
1034     if (!str) {
1035 siliconforks 507 js_free(chars);
1036 siliconforks 332 ok = JS_FALSE;
1037     goto out;
1038     }
1039     *vp = STRING_TO_JSVAL(str);
1040     ok = JS_TRUE;
1041     out:
1042     JS_POP_TEMP_ROOT(cx, &tvr);
1043     return ok;
1044    
1045     overflow:
1046 siliconforks 507 cx->free(vsharp);
1047     js_free(chars);
1048 siliconforks 332 chars = NULL;
1049     goto error;
1050     }
1051     #endif /* JS_HAS_TOSOURCE */
1052    
1053     static JSBool
1054     obj_toString(JSContext *cx, uintN argc, jsval *vp)
1055     {
1056     JSObject *obj;
1057     jschar *chars;
1058     size_t nchars;
1059     const char *clazz, *prefix;
1060     JSString *str;
1061    
1062     obj = JS_THIS_OBJECT(cx, vp);
1063     if (!obj)
1064     return JS_FALSE;
1065     obj = js_GetWrappedObject(cx, obj);
1066     clazz = OBJ_GET_CLASS(cx, obj)->name;
1067     nchars = 9 + strlen(clazz); /* 9 for "[object ]" */
1068 siliconforks 507 chars = (jschar *) cx->malloc((nchars + 1) * sizeof(jschar));
1069 siliconforks 332 if (!chars)
1070     return JS_FALSE;
1071    
1072     prefix = "[object ";
1073     nchars = 0;
1074     while ((chars[nchars] = (jschar)*prefix) != 0)
1075     nchars++, prefix++;
1076     while ((chars[nchars] = (jschar)*clazz) != 0)
1077     nchars++, clazz++;
1078     chars[nchars++] = ']';
1079     chars[nchars] = 0;
1080    
1081     str = js_NewString(cx, chars, nchars);
1082     if (!str) {
1083 siliconforks 507 cx->free(chars);
1084 siliconforks 332 return JS_FALSE;
1085     }
1086     *vp = STRING_TO_JSVAL(str);
1087     return JS_TRUE;
1088     }
1089    
1090     static JSBool
1091     obj_toLocaleString(JSContext *cx, uintN argc, jsval *vp)
1092     {
1093     jsval thisv;
1094     JSString *str;
1095    
1096     thisv = JS_THIS(cx, vp);
1097     if (JSVAL_IS_NULL(thisv))
1098     return JS_FALSE;
1099    
1100     str = js_ValueToString(cx, thisv);
1101     if (!str)
1102     return JS_FALSE;
1103    
1104     *vp = STRING_TO_JSVAL(str);
1105     return JS_TRUE;
1106     }
1107    
1108     static JSBool
1109     obj_valueOf(JSContext *cx, uintN argc, jsval *vp)
1110     {
1111     *vp = JS_THIS(cx, vp);
1112     return !JSVAL_IS_NULL(*vp);
1113     }
1114    
1115 siliconforks 460 #ifdef JS_TRACER
1116     static jsval FASTCALL
1117     Object_p_valueOf(JSContext* cx, JSObject* obj, JSString *hint)
1118     {
1119     return OBJECT_TO_JSVAL(obj);
1120     }
1121     #endif
1122    
1123 siliconforks 332 /*
1124     * Check whether principals subsumes scopeobj's principals, and return true
1125     * if so (or if scopeobj has no principals, for backward compatibility with
1126     * the JS API, which does not require principals), and false otherwise.
1127     */
1128     JSBool
1129     js_CheckPrincipalsAccess(JSContext *cx, JSObject *scopeobj,
1130     JSPrincipals *principals, JSAtom *caller)
1131     {
1132     JSSecurityCallbacks *callbacks;
1133     JSPrincipals *scopePrincipals;
1134     const char *callerstr;
1135    
1136     callbacks = JS_GetSecurityCallbacks(cx);
1137     if (callbacks && callbacks->findObjectPrincipals) {
1138     scopePrincipals = callbacks->findObjectPrincipals(cx, scopeobj);
1139     if (!principals || !scopePrincipals ||
1140     !principals->subsume(principals, scopePrincipals)) {
1141     callerstr = js_AtomToPrintableString(cx, caller);
1142     if (!callerstr)
1143     return JS_FALSE;
1144     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1145     JSMSG_BAD_INDIRECT_CALL, callerstr);
1146     return JS_FALSE;
1147     }
1148     }
1149     return JS_TRUE;
1150     }
1151    
1152     JSObject *
1153     js_CheckScopeChainValidity(JSContext *cx, JSObject *scopeobj, const char *caller)
1154     {
1155     JSClass *clasp;
1156     JSExtendedClass *xclasp;
1157     JSObject *inner;
1158    
1159     if (!scopeobj)
1160     goto bad;
1161    
1162     OBJ_TO_INNER_OBJECT(cx, scopeobj);
1163     if (!scopeobj)
1164     return NULL;
1165    
1166     inner = scopeobj;
1167    
1168     /* XXX This is an awful gross hack. */
1169     while (scopeobj) {
1170     clasp = OBJ_GET_CLASS(cx, scopeobj);
1171     if (clasp->flags & JSCLASS_IS_EXTENDED) {
1172     xclasp = (JSExtendedClass*)clasp;
1173     if (xclasp->innerObject &&
1174     xclasp->innerObject(cx, scopeobj) != scopeobj) {
1175     goto bad;
1176     }
1177     }
1178    
1179     scopeobj = OBJ_GET_PARENT(cx, scopeobj);
1180     }
1181    
1182     return inner;
1183    
1184     bad:
1185     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1186     JSMSG_BAD_INDIRECT_CALL, caller);
1187     return NULL;
1188     }
1189    
1190     const char *
1191     js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
1192     JSPrincipals *principals, uintN *linenop)
1193     {
1194     uint32 flags;
1195     #ifdef DEBUG
1196     JSSecurityCallbacks *callbacks = JS_GetSecurityCallbacks(cx);
1197     #endif
1198    
1199     JS_ASSERT(principals || !(callbacks && callbacks->findObjectPrincipals));
1200     flags = JS_GetScriptFilenameFlags(caller->script);
1201     if ((flags & JSFILENAME_PROTECTED) &&
1202     principals &&
1203     strcmp(principals->codebase, "[System Principal]")) {
1204     *linenop = 0;
1205     return principals->codebase;
1206     }
1207    
1208 siliconforks 507 if (caller->regs && js_GetOpcode(cx, caller->script, caller->regs->pc) == JSOP_EVAL) {
1209     JS_ASSERT(js_GetOpcode(cx, caller->script, caller->regs->pc + JSOP_EVAL_LENGTH) == JSOP_LINENO);
1210     *linenop = GET_UINT16(caller->regs->pc + JSOP_EVAL_LENGTH);
1211 siliconforks 332 } else {
1212 siliconforks 399 *linenop = js_FramePCToLineNumber(cx, caller);
1213 siliconforks 332 }
1214     return caller->script->filename;
1215     }
1216    
1217 siliconforks 460 #ifndef EVAL_CACHE_CHAIN_LIMIT
1218     # define EVAL_CACHE_CHAIN_LIMIT 4
1219     #endif
1220    
1221     static inline JSScript **
1222     EvalCacheHash(JSContext *cx, JSString *str)
1223     {
1224     const jschar *s;
1225     size_t n;
1226     uint32 h;
1227    
1228 siliconforks 507 str->getCharsAndLength(s, n);
1229 siliconforks 460 if (n > 100)
1230     n = 100;
1231     for (h = 0; n; s++, n--)
1232     h = JS_ROTATE_LEFT32(h, 4) ^ *s;
1233    
1234     h *= JS_GOLDEN_RATIO;
1235     h >>= 32 - JS_EVAL_CACHE_SHIFT;
1236     return &JS_SCRIPTS_TO_GC(cx)[h];
1237     }
1238    
1239 siliconforks 399 static JSBool
1240     obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1241 siliconforks 332 {
1242     JSStackFrame *fp, *caller;
1243     JSBool indirectCall;
1244 siliconforks 460 uint32 tcflags;
1245     JSPrincipals *principals;
1246 siliconforks 332 const char *file;
1247     uintN line;
1248 siliconforks 460 JSString *str;
1249 siliconforks 332 JSScript *script;
1250     JSBool ok;
1251 siliconforks 460 JSScript **bucket = NULL; /* avoid GCC warning with early decl&init */
1252 siliconforks 332 #if JS_HAS_EVAL_THIS_SCOPE
1253     JSObject *callerScopeChain = NULL, *callerVarObj = NULL;
1254     JSObject *setCallerScopeChain = NULL;
1255     JSBool setCallerVarObj = JS_FALSE;
1256     #endif
1257    
1258 siliconforks 460 fp = js_GetTopStackFrame(cx);
1259     caller = js_GetScriptedCaller(cx, fp);
1260 siliconforks 585 if (!caller) {
1261     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1262     JSMSG_BAD_INDIRECT_CALL, js_eval_str);
1263     return JS_FALSE;
1264     }
1265     indirectCall = (caller->regs && *caller->regs->pc != JSOP_EVAL);
1266 siliconforks 507 uintN staticLevel = caller->script->staticLevel + 1;
1267 siliconforks 332
1268     /*
1269 siliconforks 460 * This call to js_GetWrappedObject is safe because of the security checks
1270     * we do below. However, the control flow below is confusing, so we double
1271     * check. There are two cases:
1272     * - Direct call: This object is never used. So unwrapping can't hurt.
1273     * - Indirect call: If this object isn't already the scope chain (which
1274     * we're guaranteed to be allowed to access) then we do a security
1275     * check.
1276     */
1277     obj = js_GetWrappedObject(cx, obj);
1278    
1279     /*
1280 siliconforks 332 * Ban all indirect uses of eval (global.foo = eval; global.foo(...)) and
1281     * calls that attempt to use a non-global object as the "with" object in
1282     * the former indirect case.
1283     */
1284 siliconforks 460 {
1285     JSObject *parent = OBJ_GET_PARENT(cx, obj);
1286     if (indirectCall || parent) {
1287     uintN flags = parent
1288     ? JSREPORT_ERROR
1289     : JSREPORT_STRICT | JSREPORT_WARNING;
1290     if (!JS_ReportErrorFlagsAndNumber(cx, flags, js_GetErrorMessage, NULL,
1291     JSMSG_BAD_INDIRECT_CALL,
1292     js_eval_str)) {
1293     return JS_FALSE;
1294     }
1295 siliconforks 332 }
1296     }
1297    
1298     if (!JSVAL_IS_STRING(argv[0])) {
1299     *rval = argv[0];
1300     return JS_TRUE;
1301     }
1302    
1303     /*
1304     * If the caller is a lightweight function and doesn't have a variables
1305     * object, then we need to provide one for the compiler to stick any
1306     * declared (var) variables into.
1307     */
1308 siliconforks 585 if (!caller->varobj && !js_GetCallObject(cx, caller))
1309 siliconforks 332 return JS_FALSE;
1310    
1311 siliconforks 460 /* Accept an optional trailing argument that overrides the scope object. */
1312     JSObject *scopeobj = NULL;
1313     if (argc >= 2) {
1314     if (!js_ValueToObject(cx, argv[1], &scopeobj))
1315     return JS_FALSE;
1316     argv[1] = OBJECT_TO_JSVAL(scopeobj);
1317 siliconforks 332 }
1318    
1319     /* From here on, control must exit through label out with ok set. */
1320     MUST_FLOW_THROUGH("out");
1321     if (!scopeobj) {
1322     #if JS_HAS_EVAL_THIS_SCOPE
1323     /* If obj.eval(str), emulate 'with (obj) eval(str)' in the caller. */
1324     if (indirectCall) {
1325     callerScopeChain = js_GetScopeChain(cx, caller);
1326     if (!callerScopeChain) {
1327     ok = JS_FALSE;
1328     goto out;
1329     }
1330     OBJ_TO_INNER_OBJECT(cx, obj);
1331     if (!obj) {
1332     ok = JS_FALSE;
1333     goto out;
1334     }
1335     if (obj != callerScopeChain) {
1336     ok = js_CheckPrincipalsAccess(cx, obj,
1337 siliconforks 460 JS_StackFramePrincipals(cx, caller),
1338 siliconforks 332 cx->runtime->atomState.evalAtom);
1339     if (!ok)
1340     goto out;
1341    
1342     scopeobj = js_NewWithObject(cx, obj, callerScopeChain, -1);
1343     if (!scopeobj) {
1344     ok = JS_FALSE;
1345     goto out;
1346     }
1347    
1348     /* Set fp->scopeChain too, for the compiler. */
1349     caller->scopeChain = fp->scopeChain = scopeobj;
1350    
1351     /* Remember scopeobj so we can null its private when done. */
1352     setCallerScopeChain = scopeobj;
1353     }
1354    
1355     callerVarObj = caller->varobj;
1356     if (obj != callerVarObj) {
1357     /* Set fp->varobj too, for the compiler. */
1358     caller->varobj = fp->varobj = obj;
1359     setCallerVarObj = JS_TRUE;
1360     }
1361     }
1362     #endif
1363    
1364 siliconforks 585 /* Compile using caller's current scope object. */
1365     scopeobj = js_GetScopeChain(cx, caller);
1366     if (!scopeobj) {
1367     ok = JS_FALSE;
1368     goto out;
1369 siliconforks 332 }
1370 siliconforks 460 } else {
1371     scopeobj = js_GetWrappedObject(cx, scopeobj);
1372     OBJ_TO_INNER_OBJECT(cx, scopeobj);
1373     if (!scopeobj) {
1374     ok = JS_FALSE;
1375     goto out;
1376     }
1377     ok = js_CheckPrincipalsAccess(cx, scopeobj,
1378     JS_StackFramePrincipals(cx, caller),
1379     cx->runtime->atomState.evalAtom);
1380     if (!ok)
1381     goto out;
1382    
1383     scopeobj = js_NewWithObject(cx, scopeobj,
1384     JS_GetGlobalForObject(cx, scopeobj), -1);
1385     if (!scopeobj) {
1386     ok = JS_FALSE;
1387     goto out;
1388     }
1389     argv[1] = OBJECT_TO_JSVAL(scopeobj);
1390 siliconforks 332 }
1391    
1392     /* Ensure we compile this eval with the right object in the scope chain. */
1393     scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_eval_str);
1394     if (!scopeobj) {
1395     ok = JS_FALSE;
1396     goto out;
1397     }
1398    
1399 siliconforks 585 tcflags = TCF_COMPILE_N_GO | TCF_PUT_STATIC_LEVEL(staticLevel);
1400     principals = JS_EvalFramePrincipals(cx, fp, caller);
1401     file = js_ComputeFilename(cx, caller, principals, &line);
1402 siliconforks 332
1403 siliconforks 460 str = JSVAL_TO_STRING(argv[0]);
1404     script = NULL;
1405    
1406     /* Cache local eval scripts indexed by source qualified by scope. */
1407     bucket = EvalCacheHash(cx, str);
1408 siliconforks 507 if (!indirectCall && argc == 1 && caller->fun) {
1409 siliconforks 460 uintN count = 0;
1410     JSScript **scriptp = bucket;
1411    
1412     EVAL_CACHE_METER(probe);
1413     while ((script = *scriptp) != NULL) {
1414     if ((script->flags & JSSF_SAVED_CALLER_FUN) &&
1415 siliconforks 507 script->staticLevel == staticLevel &&
1416 siliconforks 460 script->version == cx->version &&
1417     (script->principals == principals ||
1418     (principals->subsume(principals, script->principals) &&
1419     script->principals->subsume(script->principals, principals)))) {
1420     /*
1421     * Get the prior (cache-filling) eval's saved caller function.
1422     * See JSCompiler::compileScript in jsparse.cpp.
1423     */
1424     JSFunction *fun;
1425 siliconforks 507 fun = script->getFunction(0);
1426 siliconforks 460
1427     if (fun == caller->fun) {
1428     /*
1429     * Get the source string passed for safekeeping in the
1430     * atom map by the prior eval to JSCompiler::compileScript.
1431     */
1432     JSString *src = ATOM_TO_STRING(script->atomMap.vector[0]);
1433    
1434     if (src == str || js_EqualStrings(src, str)) {
1435     /*
1436     * Source matches, qualify by comparing scopeobj to the
1437     * COMPILE_N_GO-memoized parent of the first literal
1438     * function or regexp object if any. If none, then this
1439     * script has no compiled-in dependencies on the prior
1440     * eval's scopeobj.
1441     */
1442 siliconforks 507 JSObjectArray *objarray = script->objects();
1443 siliconforks 460 int i = 1;
1444     if (objarray->length == 1) {
1445     if (script->regexpsOffset != 0) {
1446 siliconforks 507 objarray = script->regexps();
1447 siliconforks 460 i = 0;
1448     } else {
1449     EVAL_CACHE_METER(noscope);
1450     i = -1;
1451     }
1452     }
1453     if (i < 0 ||
1454     STOBJ_GET_PARENT(objarray->vector[i]) == scopeobj) {
1455 siliconforks 507 JS_ASSERT(staticLevel == script->staticLevel);
1456 siliconforks 460 EVAL_CACHE_METER(hit);
1457     *scriptp = script->u.nextToGC;
1458     script->u.nextToGC = NULL;
1459     break;
1460     }
1461     }
1462     }
1463     }
1464    
1465     if (++count == EVAL_CACHE_CHAIN_LIMIT) {
1466     script = NULL;
1467     break;
1468     }
1469     EVAL_CACHE_METER(step);
1470     scriptp = &script->u.nextToGC;
1471     }
1472     }
1473    
1474 siliconforks 332 if (!script) {
1475 siliconforks 460 script = JSCompiler::compileScript(cx, scopeobj, caller, principals, tcflags,
1476 siliconforks 507 str->chars(), str->length(),
1477 siliconforks 460 NULL, file, line, str);
1478     if (!script) {
1479     ok = JS_FALSE;
1480     goto out;
1481     }
1482 siliconforks 332 }
1483    
1484     if (argc < 2) {
1485     /* Execute using caller's new scope object (might be a Call object). */
1486 siliconforks 585 scopeobj = caller->scopeChain;
1487 siliconforks 332 }
1488    
1489     /*
1490     * Belt-and-braces: check that the lesser of eval's principals and the
1491     * caller's principals has access to scopeobj.
1492     */
1493     ok = js_CheckPrincipalsAccess(cx, scopeobj, principals,
1494     cx->runtime->atomState.evalAtom);
1495     if (ok)
1496     ok = js_Execute(cx, scopeobj, script, caller, JSFRAME_EVAL, rval);
1497    
1498 siliconforks 460 script->u.nextToGC = *bucket;
1499     *bucket = script;
1500 siliconforks 332 #ifdef CHECK_SCRIPT_OWNER
1501     script->owner = NULL;
1502     #endif
1503    
1504     out:
1505     #if JS_HAS_EVAL_THIS_SCOPE
1506     /* Restore OBJ_GET_PARENT(scopeobj) not callerScopeChain in case of Call. */
1507     if (setCallerScopeChain) {
1508     caller->scopeChain = callerScopeChain;
1509     JS_ASSERT(OBJ_GET_CLASS(cx, setCallerScopeChain) == &js_WithClass);
1510 siliconforks 507 setCallerScopeChain->setPrivate(NULL);
1511 siliconforks 332 }
1512     if (setCallerVarObj)
1513     caller->varobj = callerVarObj;
1514     #endif
1515     return ok;
1516     }
1517    
1518     #if JS_HAS_OBJ_WATCHPOINT
1519    
1520     static JSBool
1521     obj_watch_handler(JSContext *cx, JSObject *obj, jsval id, jsval old, jsval *nvp,
1522     void *closure)
1523     {
1524     JSObject *callable;
1525     JSSecurityCallbacks *callbacks;
1526     JSStackFrame *caller;
1527     JSPrincipals *subject, *watcher;
1528     JSResolvingKey key;
1529     JSResolvingEntry *entry;
1530     uint32 generation;
1531     jsval argv[3];
1532     JSBool ok;
1533    
1534     callable = (JSObject *) closure;
1535    
1536     callbacks = JS_GetSecurityCallbacks(cx);
1537     if (callbacks && callbacks->findObjectPrincipals) {
1538     /* Skip over any obj_watch_* frames between us and the real subject. */
1539 siliconforks 460 caller = js_GetScriptedCaller(cx, NULL);
1540 siliconforks 332 if (caller) {
1541     /*
1542     * Only call the watch handler if the watcher is allowed to watch
1543     * the currently executing script.
1544     */
1545     watcher = callbacks->findObjectPrincipals(cx, callable);
1546     subject = JS_StackFramePrincipals(cx, caller);
1547    
1548     if (watcher && subject && !watcher->subsume(watcher, subject)) {
1549     /* Silently don't call the watch handler. */
1550     return JS_TRUE;
1551     }
1552     }
1553     }
1554    
1555     /* Avoid recursion on (obj, id) already being watched on cx. */
1556     key.obj = obj;
1557     key.id = id;
1558     if (!js_StartResolving(cx, &key, JSRESFLAG_WATCH, &entry))
1559     return JS_FALSE;
1560     if (!entry)
1561     return JS_TRUE;
1562     generation = cx->resolvingTable->generation;
1563    
1564     argv[0] = id;
1565     argv[1] = old;
1566     argv[2] = *nvp;
1567     ok = js_InternalCall(cx, obj, OBJECT_TO_JSVAL(callable), 3, argv, nvp);
1568     js_StopResolving(cx, &key, JSRESFLAG_WATCH, entry, generation);
1569     return ok;
1570     }
1571    
1572     static JSBool
1573     obj_watch(JSContext *cx, uintN argc, jsval *vp)
1574     {
1575     JSObject *callable;
1576     jsval userid, value;
1577     jsid propid;
1578     JSObject *obj;
1579     uintN attrs;
1580    
1581     if (argc <= 1) {
1582     js_ReportMissingArg(cx, vp, 1);
1583     return JS_FALSE;
1584     }
1585    
1586     callable = js_ValueToCallableObject(cx, &vp[3], 0);
1587     if (!callable)
1588     return JS_FALSE;
1589    
1590     /* Compute the unique int/atom symbol id needed by js_LookupProperty. */
1591     userid = vp[2];
1592     if (!JS_ValueToId(cx, userid, &propid))
1593     return JS_FALSE;
1594    
1595     obj = JS_THIS_OBJECT(cx, vp);
1596 siliconforks 507 if (!obj || !obj->checkAccess(cx, propid, JSACC_WATCH, &value, &attrs))
1597 siliconforks 332 return JS_FALSE;
1598     if (attrs & JSPROP_READONLY)
1599     return JS_TRUE;
1600     *vp = JSVAL_VOID;
1601    
1602     if (OBJ_IS_DENSE_ARRAY(cx, obj) && !js_MakeArraySlow(cx, obj))
1603     return JS_FALSE;
1604     return JS_SetWatchPoint(cx, obj, userid, obj_watch_handler, callable);
1605     }
1606    
1607     static JSBool
1608     obj_unwatch(JSContext *cx, uintN argc, jsval *vp)
1609     {
1610     JSObject *obj;
1611    
1612     obj = JS_THIS_OBJECT(cx, vp);
1613     if (!obj)
1614     return JS_FALSE;
1615     *vp = JSVAL_VOID;
1616     return JS_ClearWatchPoint(cx, obj, argc != 0 ? vp[2] : JSVAL_VOID,
1617     NULL, NULL);
1618     }
1619    
1620     #endif /* JS_HAS_OBJ_WATCHPOINT */
1621    
1622     /*
1623     * Prototype and property query methods, to complement the 'in' and
1624     * 'instanceof' operators.
1625     */
1626    
1627     /* Proposed ECMA 15.2.4.5. */
1628 siliconforks 399 static JSBool
1629     obj_hasOwnProperty(JSContext *cx, uintN argc, jsval *vp)
1630 siliconforks 332 {
1631     JSObject *obj;
1632    
1633     obj = JS_THIS_OBJECT(cx, vp);
1634     return obj &&
1635     js_HasOwnPropertyHelper(cx, obj->map->ops->lookupProperty, argc, vp);
1636     }
1637    
1638     JSBool
1639     js_HasOwnPropertyHelper(JSContext *cx, JSLookupPropOp lookup, uintN argc,
1640     jsval *vp)
1641     {
1642     jsid id;
1643     JSObject *obj;
1644    
1645     if (!JS_ValueToId(cx, argc != 0 ? vp[2] : JSVAL_VOID, &id))
1646     return JS_FALSE;
1647     obj = JS_THIS_OBJECT(cx, vp);
1648     return obj && js_HasOwnProperty(cx, lookup, obj, id, vp);
1649     }
1650    
1651     JSBool
1652     js_HasOwnProperty(JSContext *cx, JSLookupPropOp lookup, JSObject *obj, jsid id,
1653     jsval *vp)
1654     {
1655     JSObject *obj2;
1656     JSProperty *prop;
1657     JSScopeProperty *sprop;
1658    
1659     if (!lookup(cx, obj, id, &obj2, &prop))
1660     return JS_FALSE;
1661     if (!prop) {
1662     *vp = JSVAL_FALSE;
1663     } else if (obj2 == obj) {
1664     *vp = JSVAL_TRUE;
1665     } else {
1666     JSClass *clasp;
1667     JSExtendedClass *xclasp;
1668     JSObject *outer;
1669    
1670     clasp = OBJ_GET_CLASS(cx, obj2);
1671     if (!(clasp->flags & JSCLASS_IS_EXTENDED) ||
1672     !(xclasp = (JSExtendedClass *) clasp)->outerObject) {
1673     outer = NULL;
1674     } else {
1675     outer = xclasp->outerObject(cx, obj2);
1676     if (!outer)
1677     return JS_FALSE;
1678     }
1679     if (outer == obj) {
1680     *vp = JSVAL_TRUE;
1681     } else if (OBJ_IS_NATIVE(obj2) && OBJ_GET_CLASS(cx, obj) == clasp) {
1682     /*
1683     * The combination of JSPROP_SHARED and JSPROP_PERMANENT in a
1684     * delegated property makes that property appear to be direct in
1685     * all delegating instances of the same native class. This hack
1686     * avoids bloating every function instance with its own 'length'
1687     * (AKA 'arity') property. But it must not extend across class
1688     * boundaries, to avoid making hasOwnProperty lie (bug 320854).
1689     *
1690     * It's not really a hack, of course: a permanent property can't
1691     * be deleted, and JSPROP_SHARED means "don't allocate a slot in
1692     * any instance, prototype or delegating". Without a slot, and
1693     * without the ability to remove and recreate (with differences)
1694     * the property, there is no way to tell whether it is directly
1695     * owned, or indirectly delegated.
1696     */
1697     sprop = (JSScopeProperty *)prop;
1698     *vp = BOOLEAN_TO_JSVAL(SPROP_IS_SHARED_PERMANENT(sprop));
1699     } else {
1700     *vp = JSVAL_FALSE;
1701     }
1702     }
1703     if (prop)
1704 siliconforks 507 obj2->dropProperty(cx, prop);
1705 siliconforks 332 return JS_TRUE;
1706     }
1707    
1708 siliconforks 399 #ifdef JS_TRACER
1709 siliconforks 460 static JSBool FASTCALL
1710 siliconforks 399 Object_p_hasOwnProperty(JSContext* cx, JSObject* obj, JSString *str)
1711     {
1712     jsid id;
1713     jsval v;
1714    
1715 siliconforks 460 if (!js_ValueToStringId(cx, STRING_TO_JSVAL(str), &id) ||
1716     !js_HasOwnProperty(cx, obj->map->ops->lookupProperty, obj, id, &v)) {
1717     js_SetBuiltinError(cx);
1718 siliconforks 399 return JSVAL_TO_BOOLEAN(JSVAL_VOID);
1719 siliconforks 460 }
1720    
1721 siliconforks 399 JS_ASSERT(JSVAL_IS_BOOLEAN(v));
1722     return JSVAL_TO_BOOLEAN(v);
1723     }
1724     #endif
1725    
1726 siliconforks 332 /* Proposed ECMA 15.2.4.6. */
1727     static JSBool
1728     obj_isPrototypeOf(JSContext *cx, uintN argc, jsval *vp)
1729     {
1730     JSBool b;
1731    
1732     if (!js_IsDelegate(cx, JS_THIS_OBJECT(cx, vp),
1733     argc != 0 ? vp[2] : JSVAL_VOID, &b)) {
1734     return JS_FALSE;
1735     }
1736     *vp = BOOLEAN_TO_JSVAL(b);
1737     return JS_TRUE;
1738     }
1739    
1740     /* Proposed ECMA 15.2.4.7. */
1741 siliconforks 399 static JSBool
1742     obj_propertyIsEnumerable(JSContext *cx, uintN argc, jsval *vp)
1743 siliconforks 332 {
1744     jsid id;
1745     JSObject *obj;
1746    
1747     if (!JS_ValueToId(cx, argc != 0 ? vp[2] : JSVAL_VOID, &id))
1748     return JS_FALSE;
1749    
1750     obj = JS_THIS_OBJECT(cx, vp);
1751     return obj && js_PropertyIsEnumerable(cx, obj, id, vp);
1752     }
1753    
1754 siliconforks 399 #ifdef JS_TRACER
1755 siliconforks 460 static JSBool FASTCALL
1756 siliconforks 399 Object_p_propertyIsEnumerable(JSContext* cx, JSObject* obj, JSString *str)
1757     {
1758     jsid id = ATOM_TO_JSID(STRING_TO_JSVAL(str));
1759     jsval v;
1760 siliconforks 460
1761     if (!js_PropertyIsEnumerable(cx, obj, id, &v)) {
1762     js_SetBuiltinError(cx);
1763 siliconforks 399 return JSVAL_TO_BOOLEAN(JSVAL_VOID);
1764 siliconforks 460 }
1765    
1766 siliconforks 399 JS_ASSERT(JSVAL_IS_BOOLEAN(v));
1767     return JSVAL_TO_BOOLEAN(v);
1768     }
1769     #endif
1770    
1771 siliconforks 332 JSBool
1772     js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
1773     {
1774     JSObject *pobj;
1775     uintN attrs;
1776     JSProperty *prop;
1777     JSBool ok;
1778    
1779 siliconforks 507 if (!obj->lookupProperty(cx, id, &pobj, &prop))
1780 siliconforks 332 return JS_FALSE;
1781    
1782     if (!prop) {
1783     *vp = JSVAL_FALSE;
1784     return JS_TRUE;
1785     }
1786    
1787     /*
1788     * XXX ECMA spec error compatible: return false unless hasOwnProperty.
1789     * The ECMA spec really should be fixed so propertyIsEnumerable and the
1790     * for..in loop agree on whether prototype properties are enumerable,
1791     * obviously by fixing this method (not by breaking the for..in loop!).
1792     *
1793     * We check here for shared permanent prototype properties, which should
1794     * be treated as if they are local to obj. They are an implementation
1795     * technique used to satisfy ECMA requirements; users should not be able
1796     * to distinguish a shared permanent proto-property from a local one.
1797     */
1798     if (pobj != obj &&
1799     !(OBJ_IS_NATIVE(pobj) &&
1800     SPROP_IS_SHARED_PERMANENT((JSScopeProperty *)prop))) {
1801 siliconforks 507 pobj->dropProperty(cx, prop);
1802 siliconforks 332 *vp = JSVAL_FALSE;
1803     return JS_TRUE;
1804     }
1805    
1806 siliconforks 507 ok = pobj->getAttributes(cx, id, prop, &attrs);
1807     pobj->dropProperty(cx, prop);
1808 siliconforks 332 if (ok)
1809     *vp = BOOLEAN_TO_JSVAL((attrs & JSPROP_ENUMERATE) != 0);
1810     return ok;
1811     }
1812    
1813     #if JS_HAS_GETTER_SETTER
1814 siliconforks 460 JS_FRIEND_API(JSBool)
1815     js_obj_defineGetter(JSContext *cx, uintN argc, jsval *vp)
1816 siliconforks 332 {
1817     jsval fval, junk;
1818     jsid id;
1819     JSObject *obj;
1820     uintN attrs;
1821    
1822     if (argc <= 1 || JS_TypeOfValue(cx, vp[3]) != JSTYPE_FUNCTION) {
1823     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1824     JSMSG_BAD_GETTER_OR_SETTER,
1825     js_getter_str);
1826     return JS_FALSE;
1827     }
1828     fval = vp[3];
1829    
1830     if (!JS_ValueToId(cx, vp[2], &id))
1831     return JS_FALSE;
1832     obj = JS_THIS_OBJECT(cx, vp);
1833     if (!obj || !js_CheckRedeclaration(cx, obj, id, JSPROP_GETTER, NULL, NULL))
1834     return JS_FALSE;
1835     /*
1836     * Getters and setters are just like watchpoints from an access
1837     * control point of view.
1838     */
1839 siliconforks 507 if (!obj->checkAccess(cx, id, JSACC_WATCH, &junk, &attrs))
1840 siliconforks 332 return JS_FALSE;
1841     *vp = JSVAL_VOID;
1842 siliconforks 507 return obj->defineProperty(cx, id, JSVAL_VOID,
1843     js_CastAsPropertyOp(JSVAL_TO_OBJECT(fval)), JS_PropertyStub,
1844     JSPROP_ENUMERATE | JSPROP_GETTER | JSPROP_SHARED);
1845 siliconforks 332 }
1846    
1847 siliconforks 460 JS_FRIEND_API(JSBool)
1848     js_obj_defineSetter(JSContext *cx, uintN argc, jsval *vp)
1849 siliconforks 332 {
1850     jsval fval, junk;
1851     jsid id;
1852     JSObject *obj;
1853     uintN attrs;
1854    
1855     if (argc <= 1 || JS_TypeOfValue(cx, vp[3]) != JSTYPE_FUNCTION) {
1856     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1857     JSMSG_BAD_GETTER_OR_SETTER,
1858     js_setter_str);
1859     return JS_FALSE;
1860     }
1861     fval = vp[3];
1862    
1863     if (!JS_ValueToId(cx, vp[2], &id))
1864     return JS_FALSE;
1865     obj = JS_THIS_OBJECT(cx, vp);
1866     if (!obj || !js_CheckRedeclaration(cx, obj, id, JSPROP_SETTER, NULL, NULL))
1867     return JS_FALSE;
1868     /*
1869     * Getters and setters are just like watchpoints from an access
1870     * control point of view.
1871     */
1872 siliconforks 507 if (!obj->checkAccess(cx, id, JSACC_WATCH, &junk, &attrs))
1873 siliconforks 332 return JS_FALSE;
1874     *vp = JSVAL_VOID;
1875 siliconforks 507 return obj->defineProperty(cx, id, JSVAL_VOID,
1876     JS_PropertyStub, js_CastAsPropertyOp(JSVAL_TO_OBJECT(fval)),
1877     JSPROP_ENUMERATE | JSPROP_SETTER | JSPROP_SHARED);
1878 siliconforks 332 }
1879    
1880     static JSBool
1881     obj_lookupGetter(JSContext *cx, uintN argc, jsval *vp)
1882     {
1883     jsid id;
1884     JSObject *obj, *pobj;
1885     JSProperty *prop;
1886     JSScopeProperty *sprop;
1887    
1888     if (!JS_ValueToId(cx, argc != 0 ? vp[2] : JSVAL_VOID, &id))
1889     return JS_FALSE;
1890     obj = JS_THIS_OBJECT(cx, vp);
1891 siliconforks 507 if (!obj || !obj->lookupProperty(cx, id, &pobj, &prop))
1892 siliconforks 332 return JS_FALSE;
1893     *vp = JSVAL_VOID;
1894     if (prop) {
1895     if (OBJ_IS_NATIVE(pobj)) {
1896     sprop = (JSScopeProperty *) prop;
1897     if (sprop->attrs & JSPROP_GETTER)
1898 siliconforks 460 *vp = js_CastAsObjectJSVal(sprop->getter);
1899 siliconforks 332 }
1900 siliconforks 507 pobj->dropProperty(cx, prop);
1901 siliconforks 332 }
1902     return JS_TRUE;
1903     }
1904    
1905     static JSBool
1906     obj_lookupSetter(JSContext *cx, uintN argc, jsval *vp)
1907     {
1908     jsid id;
1909     JSObject *obj, *pobj;
1910     JSProperty *prop;
1911     JSScopeProperty *sprop;
1912    
1913     if (!JS_ValueToId(cx, argc != 0 ? vp[2] : JSVAL_VOID, &id))
1914     return JS_FALSE;
1915     obj = JS_THIS_OBJECT(cx, vp);
1916 siliconforks 507 if (!obj || !obj->lookupProperty(cx, id, &pobj, &prop))
1917 siliconforks 332 return JS_FALSE;
1918     *vp = JSVAL_VOID;
1919     if (prop) {
1920     if (OBJ_IS_NATIVE(pobj)) {
1921     sprop = (JSScopeProperty *) prop;
1922     if (sprop->attrs & JSPROP_SETTER)
1923 siliconforks 460 *vp = js_CastAsObjectJSVal(sprop->setter);
1924 siliconforks 332 }
1925 siliconforks 507 pobj->dropProperty(cx, prop);
1926 siliconforks 332 }
1927     return JS_TRUE;
1928     }
1929     #endif /* JS_HAS_GETTER_SETTER */
1930    
1931     JSBool
1932     obj_getPrototypeOf(JSContext *cx, uintN argc, jsval *vp)
1933     {
1934     JSObject *obj;
1935     uintN attrs;
1936    
1937     if (argc == 0) {
1938     js_ReportMissingArg(cx, vp, 0);
1939     return JS_FALSE;
1940     }
1941    
1942     obj = js_ValueToNonNullObject(cx, vp[2]);
1943     if (!obj)
1944     return JS_FALSE;
1945     vp[2] = OBJECT_TO_JSVAL(obj);
1946    
1947 siliconforks 507 return obj->checkAccess(cx, ATOM_TO_JSID(cx->runtime->atomState.protoAtom),
1948 siliconforks 332 JSACC_PROTO, vp, &attrs);
1949     }
1950    
1951     #if JS_HAS_OBJ_WATCHPOINT
1952     const char js_watch_str[] = "watch";
1953     const char js_unwatch_str[] = "unwatch";
1954     #endif
1955     const char js_hasOwnProperty_str[] = "hasOwnProperty";
1956     const char js_isPrototypeOf_str[] = "isPrototypeOf";
1957     const char js_propertyIsEnumerable_str[] = "propertyIsEnumerable";
1958     #if JS_HAS_GETTER_SETTER
1959     const char js_defineGetter_str[] = "__defineGetter__";
1960     const char js_defineSetter_str[] = "__defineSetter__";
1961     const char js_lookupGetter_str[] = "__lookupGetter__";
1962     const char js_lookupSetter_str[] = "__lookupSetter__";
1963     #endif
1964    
1965 siliconforks 460 JS_DEFINE_TRCINFO_1(obj_valueOf,
1966     (3, (static, JSVAL, Object_p_valueOf, CONTEXT, THIS, STRING, 0, 0)))
1967 siliconforks 399 JS_DEFINE_TRCINFO_1(obj_hasOwnProperty,
1968 siliconforks 460 (3, (static, BOOL_FAIL, Object_p_hasOwnProperty, CONTEXT, THIS, STRING, 0, 0)))
1969 siliconforks 399 JS_DEFINE_TRCINFO_1(obj_propertyIsEnumerable,
1970 siliconforks 460 (3, (static, BOOL_FAIL, Object_p_propertyIsEnumerable, CONTEXT, THIS, STRING, 0, 0)))
1971 siliconforks 399
1972 siliconforks 332 static JSFunctionSpec object_methods[] = {
1973     #if JS_HAS_TOSOURCE
1974     JS_FN(js_toSource_str, obj_toSource, 0,0),
1975     #endif
1976     JS_FN(js_toString_str, obj_toString, 0,0),
1977     JS_FN(js_toLocaleString_str, obj_toLocaleString, 0,0),
1978 siliconforks 507 JS_TN(js_valueOf_str, obj_valueOf, 0,0, &obj_valueOf_trcinfo),
1979 siliconforks 332 #if JS_HAS_OBJ_WATCHPOINT
1980     JS_FN(js_watch_str, obj_watch, 2,0),
1981     JS_FN(js_unwatch_str, obj_unwatch, 1,0),
1982     #endif
1983 siliconforks 507 JS_TN(js_hasOwnProperty_str, obj_hasOwnProperty, 1,0, &obj_hasOwnProperty_trcinfo),
1984 siliconforks 332 JS_FN(js_isPrototypeOf_str, obj_isPrototypeOf, 1,0),
1985 siliconforks 507 JS_TN(js_propertyIsEnumerable_str, obj_propertyIsEnumerable, 1,0, &obj_propertyIsEnumerable_trcinfo),
1986 siliconforks 332 #if JS_HAS_GETTER_SETTER
1987 siliconforks 460 JS_FN(js_defineGetter_str, js_obj_defineGetter, 2,0),
1988     JS_FN(js_defineSetter_str, js_obj_defineSetter, 2,0),
1989 siliconforks 332 JS_FN(js_lookupGetter_str, obj_lookupGetter, 1,0),
1990     JS_FN(js_lookupSetter_str, obj_lookupSetter, 1,0),
1991     #endif
1992     JS_FS_END
1993     };
1994    
1995     static JSFunctionSpec object_static_methods[] = {
1996 siliconforks 399 JS_FN("getPrototypeOf", obj_getPrototypeOf, 1,0),
1997 siliconforks 332 JS_FS_END
1998     };
1999    
2000 siliconforks 507 static bool
2001     AllocSlots(JSContext *cx, JSObject *obj, size_t nslots);
2002    
2003     static inline bool
2004     InitScopeForObject(JSContext* cx, JSObject* obj, JSObject* proto, JSObjectOps* ops)
2005     {
2006     JS_ASSERT(OPS_IS_NATIVE(ops));
2007     JS_ASSERT(proto == OBJ_GET_PROTO(cx, obj));
2008    
2009     /* Share proto's emptyScope only if obj is similar to proto. */
2010     JSClass *clasp = OBJ_GET_CLASS(cx, obj);
2011     JSScope *scope;
2012     if (proto && OBJ_IS_NATIVE(proto) &&
2013     (scope = OBJ_SCOPE(proto))->canProvideEmptyScope(ops, clasp)) {
2014     scope = scope->getEmptyScope(cx, clasp);
2015     if (!scope)
2016     goto bad;
2017     } else {
2018     scope = JSScope::create(cx, ops, clasp, obj, js_GenerateShape(cx, false));
2019     if (!scope)
2020     goto bad;
2021    
2022     /* Let JSScope::create set freeslot so as to reserve slots. */
2023     JS_ASSERT(scope->freeslot >= JSSLOT_PRIVATE);
2024     if (scope->freeslot > JS_INITIAL_NSLOTS &&
2025     !AllocSlots(cx, obj, scope->freeslot)) {
2026     JSScope::destroy(cx, scope);
2027     goto bad;
2028     }
2029     }
2030     obj->map = scope;
2031     return true;
2032    
2033     bad:
2034     /* The GC nulls map initially. It should still be null on error. */
2035     JS_ASSERT(!obj->map);
2036     return false;
2037     }
2038    
2039     JSObject *
2040     js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
2041     JSObject *parent, size_t objectSize)
2042     {
2043     #ifdef INCLUDE_MOZILLA_DTRACE
2044     if (JAVASCRIPT_OBJECT_CREATE_START_ENABLED())
2045     jsdtrace_object_create_start(cx->fp, clasp);
2046     #endif
2047    
2048     /* Assert that the class is a proper class. */
2049     JS_ASSERT_IF(clasp->flags & JSCLASS_IS_EXTENDED,
2050     ((JSExtendedClass *)clasp)->equality);
2051    
2052     /* Always call the class's getObjectOps hook if it has one. */
2053     JSObjectOps *ops = clasp->getObjectOps
2054     ? clasp->getObjectOps(cx, clasp)
2055     : &js_ObjectOps;
2056    
2057     /*
2058     * Allocate an object from the GC heap and initialize all its fields before
2059     * doing any operation that can potentially trigger GC. Functions have a
2060     * larger non-standard allocation size.
2061     */
2062     JSObject* obj;
2063     if (clasp == &js_FunctionClass && !objectSize) {
2064     obj = (JSObject*) js_NewGCFunction(cx, GCX_OBJECT);
2065     #ifdef DEBUG
2066     memset((uint8 *) obj + sizeof(JSObject), JS_FREE_PATTERN,
2067     sizeof(JSFunction) - sizeof(JSObject));
2068     #endif
2069     } else {
2070     JS_ASSERT(!objectSize || objectSize == sizeof(JSObject));
2071     obj = js_NewGCObject(cx, GCX_OBJECT);
2072     }
2073     if (!obj)
2074     goto out;
2075    
2076     /*
2077     * Default parent to the parent of the prototype, which was set from
2078     * the parent of the prototype's constructor.
2079     */
2080     obj->init(clasp,
2081     proto,
2082     (!parent && proto) ? proto->getParent() : parent,
2083     JSObject::defaultPrivate(clasp));
2084    
2085     if (OPS_IS_NATIVE(ops)) {
2086     if (!InitScopeForObject(cx, obj, proto, ops)) {
2087     obj = NULL;
2088     goto out;
2089     }
2090     } else {
2091     JS_ASSERT(ops->objectMap->ops == ops);
2092     obj->map = const_cast<JSObjectMap *>(ops->objectMap);
2093     }
2094    
2095     /* Check that the newborn root still holds the object. */
2096     JS_ASSERT_IF(!cx->localRootStack, cx->weakRoots.newborn[GCX_OBJECT] == obj);
2097    
2098     /*
2099     * Do not call debug hooks on trace, because we might be in a non-_FAIL
2100     * builtin. See bug 481444.
2101     */
2102     if (cx->debugHooks->objectHook && !JS_ON_TRACE(cx)) {
2103     JSAutoTempValueRooter tvr(cx, obj);
2104     JS_KEEP_ATOMS(cx->runtime);
2105     cx->debugHooks->objectHook(cx, obj, JS_TRUE,
2106     cx->debugHooks->objectHookData);
2107     JS_UNKEEP_ATOMS(cx->runtime);
2108     cx->weakRoots.newborn[GCX_OBJECT] = obj;
2109     }
2110    
2111     out:
2112     #ifdef INCLUDE_MOZILLA_DTRACE
2113     if (JAVASCRIPT_OBJECT_CREATE_ENABLED())
2114     jsdtrace_object_create(cx, clasp, obj);
2115     if (JAVASCRIPT_OBJECT_CREATE_DONE_ENABLED())
2116     jsdtrace_object_create_done(cx->fp, clasp);
2117     #endif
2118     return obj;
2119     }
2120    
2121     JSObject *
2122     js_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto,
2123     JSObject *parent, size_t objectSize)
2124     {
2125     jsid id;
2126    
2127     /* Bootstrap the ur-object, and make it the default prototype object. */
2128     if (!proto) {
2129     if (!js_GetClassId(cx, clasp, &id))
2130     return NULL;
2131     if (!js_GetClassPrototype(cx, parent, id, &proto))
2132     return NULL;
2133     if (!proto &&
2134     !js_GetClassPrototype(cx, parent, INT_TO_JSID(JSProto_Object),
2135     &proto)) {
2136     return NULL;
2137     }
2138     }
2139    
2140     return js_NewObjectWithGivenProto(cx, clasp, proto, parent, objectSize);
2141     }
2142    
2143 siliconforks 332 JSBool
2144     js_Object(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2145     {
2146     if (argc == 0) {
2147     /* Trigger logic below to construct a blank object. */
2148     obj = NULL;
2149     } else {
2150     /* If argv[0] is null or undefined, obj comes back null. */
2151     if (!js_ValueToObject(cx, argv[0], &obj))
2152     return JS_FALSE;
2153     }
2154     if (!obj) {
2155     JS_ASSERT(!argc || JSVAL_IS_NULL(argv[0]) || JSVAL_IS_VOID(argv[0]));
2156 siliconforks 460 if (JS_IsConstructing(cx))
2157 siliconforks 332 return JS_TRUE;
2158 siliconforks 507 obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL);
2159 siliconforks 332 if (!obj)
2160     return JS_FALSE;
2161     }
2162     *rval = OBJECT_TO_JSVAL(obj);
2163     return JS_TRUE;
2164     }
2165    
2166 siliconforks 507 #ifdef JS_TRACER
2167    
2168     JSObject*
2169     js_NewObjectWithClassProto(JSContext *cx, JSClass *clasp, JSObject *proto,
2170     jsval privateSlotValue)
2171 siliconforks 460 {
2172 siliconforks 507 JS_ASSERT(!clasp->getObjectOps);
2173     JS_ASSERT(proto->map->ops == &js_ObjectOps);
2174 siliconforks 460
2175 siliconforks 507 JSObject* obj = js_NewGCObject(cx, GCX_OBJECT);
2176     if (!obj)
2177     return NULL;
2178 siliconforks 460
2179 siliconforks 507 obj->initSharingEmptyScope(clasp, proto, proto->getParent(), privateSlotValue);
2180     return obj;
2181     }
2182 siliconforks 460
2183 siliconforks 507 JSObject* FASTCALL
2184     js_Object_tn(JSContext* cx, JSObject* proto)
2185     {
2186     JS_ASSERT(!(js_ObjectClass.flags & JSCLASS_HAS_PRIVATE));
2187     return js_NewObjectWithClassProto(cx, &js_ObjectClass, proto, JSVAL_VOID);
2188 siliconforks 460 }
2189    
2190 siliconforks 507 JS_DEFINE_TRCINFO_1(js_Object,
2191     (2, (extern, CONSTRUCTOR_RETRY, js_Object_tn, CONTEXT, CALLEE_PROTOTYPE, 0, 0)))
2192 siliconforks 460
2193     static inline JSObject*
2194 siliconforks 507 NewNativeObject(JSContext* cx, JSClass* clasp, JSObject* proto,
2195     JSObject *parent, jsval privateSlotValue)
2196 siliconforks 460 {
2197     JS_ASSERT(JS_ON_TRACE(cx));
2198 siliconforks 507 JSObject* obj = js_NewGCObject(cx, GCX_OBJECT);
2199 siliconforks 460 if (!obj)
2200     return NULL;
2201    
2202 siliconforks 507 obj->init(clasp, proto, parent, privateSlotValue);
2203 siliconforks 460 return InitScopeForObject(cx, obj, proto, &js_ObjectOps) ? obj : NULL;
2204     }
2205    
2206     JSObject* FASTCALL
2207     js_NewInstance(JSContext *cx, JSClass *clasp, JSObject *ctor)
2208     {
2209     JS_ASSERT(HAS_FUNCTION_CLASS(ctor));
2210    
2211     JSAtom *atom = cx->runtime->atomState.classPrototypeAtom;
2212    
2213     JSScope *scope = OBJ_SCOPE(ctor);
2214     #ifdef JS_THREADSAFE
2215     if (scope->title.ownercx != cx)
2216     return NULL;
2217     #endif
2218 siliconforks 507 if (!scope->owned()) {
2219 siliconforks 460 scope = js_GetMutableScope(cx, ctor);
2220     if (!scope)
2221     return NULL;
2222     }
2223    
2224 siliconforks 507 JSScopeProperty *sprop = scope->lookup(ATOM_TO_JSID(atom));
2225 siliconforks 460 jsval pval = sprop ? STOBJ_GET_SLOT(ctor, sprop->slot) : JSVAL_HOLE;
2226    
2227     JSObject *proto;
2228     if (!JSVAL_IS_PRIMITIVE(pval)) {
2229     /* An object in ctor.prototype, let's use it as the new instance's proto. */
2230     proto = JSVAL_TO_OBJECT(pval);
2231     } else if (pval == JSVAL_HOLE) {
2232     /* No ctor.prototype yet, inline and optimize fun_resolve's prototype code. */
2233 siliconforks 507 proto = js_NewObject(cx, clasp, NULL, OBJ_GET_PARENT(cx, ctor));
2234 siliconforks 460 if (!proto)
2235     return NULL;
2236     if (!js_SetClassPrototype(cx, ctor, proto, JSPROP_ENUMERATE | JSPROP_PERMANENT))
2237     return NULL;
2238     } else {
2239     /* Primitive value in .prototype means we use Object.prototype for proto. */
2240     if (!js_GetClassPrototype(cx, JSVAL_TO_OBJECT(ctor->fslots[JSSLOT_PARENT]),
2241     INT_TO_JSID(JSProto_Object), &proto)) {
2242     return NULL;
2243     }
2244     }
2245    
2246 siliconforks 507 return NewNativeObject(cx, clasp, proto, ctor->getParent(),
2247     JSObject::defaultPrivate(clasp));
2248 siliconforks 460 }
2249    
2250     JS_DEFINE_CALLINFO_3(extern, CONSTRUCTOR_RETRY, js_NewInstance, CONTEXT, CLASS, OBJECT, 0, 0)
2251    
2252     #else /* !JS_TRACER */
2253    
2254     # define js_Object_trcinfo NULL
2255    
2256     #endif /* !JS_TRACER */
2257    
2258 siliconforks 332 /*
2259 siliconforks 460 * Given pc pointing after a property accessing bytecode, return true if the
2260     * access is "object-detecting" in the sense used by web scripts, e.g., when
2261     * checking whether document.all is defined.
2262     */
2263 siliconforks 507 JS_REQUIRES_STACK JSBool
2264 siliconforks 460 Detecting(JSContext *cx, jsbytecode *pc)
2265     {
2266     JSScript *script;
2267     jsbytecode *endpc;
2268     JSOp op;
2269     JSAtom *atom;
2270    
2271     script = cx->fp->script;
2272     endpc = script->code + script->length;
2273     for (;; pc += js_CodeSpec[op].length) {
2274 siliconforks 507 JS_ASSERT_IF(!cx->fp->imacpc, script->code <= pc && pc < endpc);
2275 siliconforks 460
2276     /* General case: a branch or equality op follows the access. */
2277     op = js_GetOpcode(cx, script, pc);
2278     if (js_CodeSpec[op].format & JOF_DETECTING)
2279     return JS_TRUE;
2280    
2281     switch (op) {
2282     case JSOP_NULL:
2283     /*
2284     * Special case #1: handle (document.all == null). Don't sweat
2285     * about JS1.2's revision of the equality operators here.
2286     */
2287     if (++pc < endpc) {
2288     op = js_GetOpcode(cx, script, pc);
2289     return *pc == JSOP_EQ || *pc == JSOP_NE;
2290     }
2291     return JS_FALSE;
2292    
2293     case JSOP_NAME:
2294     /*
2295     * Special case #2: handle (document.all == undefined). Don't
2296     * worry about someone redefining undefined, which was added by
2297     * Edition 3, so is read/write for backward compatibility.
2298     */
2299     GET_ATOM_FROM_BYTECODE(script, pc, 0, atom);
2300     if (atom == cx->runtime->atomState.typeAtoms[JSTYPE_VOID] &&
2301     (pc += js_CodeSpec[op].length) < endpc) {
2302     op = js_GetOpcode(cx, script, pc);
2303     return op == JSOP_EQ || op == JSOP_NE ||
2304     op == JSOP_STRICTEQ || op == JSOP_STRICTNE;
2305     }
2306     return JS_FALSE;
2307    
2308     default:
2309     /*
2310     * At this point, anything but an extended atom index prefix means
2311     * we're not detecting.
2312     */
2313     if (!(js_CodeSpec[op].format & JOF_INDEXBASE))
2314     return JS_FALSE;
2315     break;
2316     }
2317     }
2318     }
2319    
2320     /*
2321     * Infer lookup flags from the currently executing bytecode. This does
2322     * not attempt to infer JSRESOLVE_WITH, because the current bytecode
2323     * does not indicate whether we are in a with statement. Return defaultFlags
2324     * if a currently executing bytecode cannot be determined.
2325     */
2326 siliconforks 507 uintN
2327     js_InferFlags(JSContext *cx, uintN defaultFlags)
2328 siliconforks 460 {
2329 siliconforks 507 #ifdef JS_TRACER
2330     if (JS_ON_TRACE(cx))
2331     return cx->bailExit->lookupFlags;
2332     #endif
2333    
2334     JS_ASSERT_NOT_ON_TRACE(cx);
2335    
2336 siliconforks 460 JSStackFrame *fp;
2337     jsbytecode *pc;
2338     const JSCodeSpec *cs;
2339     uint32 format;
2340     uintN flags = 0;
2341    
2342     fp = js_GetTopStackFrame(cx);
2343     if (!fp || !fp->regs)
2344     return defaultFlags;
2345     pc = fp->regs->pc;
2346     cs = &js_CodeSpec[js_GetOpcode(cx, fp->script, pc)];
2347     format = cs->format;
2348     if (JOF_MODE(format) != JOF_NAME)
2349     flags |= JSRESOLVE_QUALIFIED;
2350     if ((format & (JOF_SET | JOF_FOR)) ||
2351     (fp->flags & JSFRAME_ASSIGNING)) {
2352     flags |= JSRESOLVE_ASSIGNING;
2353 siliconforks 507 } else if (cs->length >= 0) {
2354 siliconforks 460 pc += cs->length;
2355     if (pc < cx->fp->script->code + cx->fp->script->length && Detecting(cx, pc))
2356     flags |= JSRESOLVE_DETECTING;
2357     }
2358     if (format & JOF_DECLARING)
2359     flags |= JSRESOLVE_DECLARING;
2360     return flags;
2361     }
2362    
2363     /*
2364 siliconforks 332 * ObjectOps and Class for with-statement stack objects.
2365     */
2366     static JSBool
2367     with_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
2368     JSProperty **propp)
2369     {
2370 siliconforks 460 /* Fixes bug 463997 */
2371     uintN flags = cx->resolveFlags;
2372     if (flags == JSRESOLVE_INFER)
2373 siliconforks 507 flags = js_InferFlags(cx, flags);
2374 siliconforks 460 flags |= JSRESOLVE_WITH;
2375     JSAutoResolveFlags rf(cx, flags);
2376 siliconforks 332 JSObject *proto = OBJ_GET_PROTO(cx, obj);
2377     if (!proto)
2378     return js_LookupProperty(cx, obj, id, objp, propp);
2379 siliconforks 507 return proto->lookupProperty(cx, id, objp, propp);
2380 siliconforks 332 }
2381    
2382     static JSBool
2383     with_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
2384     {
2385     JSObject *proto = OBJ_GET_PROTO(cx, obj);
2386     if (!proto)
2387     return js_GetProperty(cx, obj, id, vp);
2388 siliconforks 507 return proto->getProperty(cx, id, vp);
2389 siliconforks 332 }
2390    
2391     static JSBool
2392     with_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
2393     {
2394     JSObject *proto = OBJ_GET_PROTO(cx, obj);
2395     if (!proto)
2396     return js_SetProperty(cx, obj, id, vp);
2397 siliconforks 507 return proto->setProperty(cx, id, vp);
2398 siliconforks 332 }
2399    
2400     static JSBool
2401     with_GetAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop,
2402     uintN *attrsp)
2403     {
2404     JSObject *proto = OBJ_GET_PROTO(cx, obj);
2405     if (!proto)
2406     return js_GetAttributes(cx, obj, id, prop, attrsp);
2407 siliconforks 507 return proto->getAttributes(cx, id, prop, attrsp);
2408 siliconforks 332 }
2409    
2410     static JSBool
2411     with_SetAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop,
2412     uintN *attrsp)
2413     {
2414     JSObject *proto = OBJ_GET_PROTO(cx, obj);
2415     if (!proto)
2416     return js_SetAttributes(cx, obj, id, prop, attrsp);
2417 siliconforks 507 return proto->setAttributes(cx, id, prop, attrsp);
2418 siliconforks 332 }
2419    
2420     static JSBool
2421     with_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
2422     {
2423     JSObject *proto = OBJ_GET_PROTO(cx, obj);
2424     if (!proto)
2425     return js_DeleteProperty(cx, obj, id, rval);
2426 siliconforks 507 return proto->deleteProperty(cx, id, rval);
2427 siliconforks 332 }
2428    
2429     static JSBool
2430     with_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp)
2431     {
2432     JSObject *proto = OBJ_GET_PROTO(cx, obj);
2433     if (!proto)
2434     return js_DefaultValue(cx, obj, hint, vp);
2435 siliconforks 507 return proto->defaultValue(cx, hint, vp);
2436 siliconforks 332 }
2437    
2438     static JSBool
2439     with_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
2440     jsval *statep, jsid *idp)
2441     {
2442     JSObject *proto = OBJ_GET_PROTO(cx, obj);
2443     if (!proto)
2444     return js_Enumerate(cx, obj, enum_op, statep, idp);
2445 siliconforks 507 return proto->enumerate(cx, enum_op, statep, idp);
2446 siliconforks 332 }
2447    
2448     static JSBool
2449     with_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
2450     jsval *vp, uintN *attrsp)
2451     {
2452     JSObject *proto = OBJ_GET_PROTO(cx, obj);
2453     if (!proto)
2454     return js_CheckAccess(cx, obj, id, mode, vp, attrsp);
2455 siliconforks 507 return proto->checkAccess(cx, id, mode, vp, attrsp);
2456 siliconforks 332 }
2457    
2458     static JSObject *
2459     with_ThisObject(JSContext *cx, JSObject *obj)
2460     {
2461     JSObject *proto = OBJ_GET_PROTO(cx, obj);
2462     if (!proto)
2463     return obj;
2464 siliconforks 507 return proto->thisObject(cx);
2465 siliconforks 332 }
2466    
2467     JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps = {
2468 siliconforks 460 NULL,
2469 siliconforks 332 with_LookupProperty, js_DefineProperty,
2470     with_GetProperty, with_SetProperty,
2471     with_GetAttributes, with_SetAttributes,
2472     with_DeleteProperty, with_DefaultValue,
2473     with_Enumerate, with_CheckAccess,
2474     with_ThisObject, NATIVE_DROP_PROPERTY,
2475     NULL, NULL,
2476 siliconforks 460 NULL, js_TraceObject,
2477 siliconforks 507 js_Clear
2478 siliconforks 332 };
2479    
2480     static JSObjectOps *
2481     with_getObjectOps(JSContext *cx, JSClass *clasp)
2482     {
2483     return &js_WithObjectOps;
2484     }
2485    
2486     JSClass js_WithClass = {
2487     "With",
2488     JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_IS_ANONYMOUS,
2489     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
2490 siliconforks 507 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL,
2491 siliconforks 332 with_getObjectOps,
2492     0,0,0,0,0,0,0
2493     };
2494    
2495 siliconforks 460 JS_REQUIRES_STACK JSObject *
2496 siliconforks 332 js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
2497     {
2498     JSObject *obj;
2499    
2500 siliconforks 507 obj = js_NewObject(cx, &js_WithClass, proto, parent);
2501 siliconforks 332 if (!obj)
2502     return NULL;
2503 siliconforks 507 obj->setPrivate(cx->fp);
2504 siliconforks 332 OBJ_SET_BLOCK_DEPTH(cx, obj, depth);
2505     return obj;
2506     }
2507    
2508     JSObject *
2509     js_NewBlockObject(JSContext *cx)
2510     {
2511     /*
2512     * Null obj's proto slot so that Object.prototype.* does not pollute block
2513 siliconforks 460 * scopes and to give the block object its own scope.
2514 siliconforks 332 */
2515 siliconforks 507 JSObject *blockObj = js_NewObjectWithGivenProto(cx, &js_BlockClass, NULL, NULL);
2516 siliconforks 460 JS_ASSERT_IF(blockObj, !OBJ_IS_CLONED_BLOCK(blockObj));
2517     return blockObj;
2518 siliconforks 332 }
2519    
2520     JSObject *
2521 siliconforks 507 js_CloneBlockObject(JSContext *cx, JSObject *proto, JSStackFrame *fp)
2522 siliconforks 332 {
2523 siliconforks 507 JS_ASSERT(!OBJ_IS_CLONED_BLOCK(proto));
2524     JS_ASSERT(STOBJ_GET_CLASS(proto) == &js_BlockClass);
2525 siliconforks 332
2526 siliconforks 507