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

Annotation of /trunk/js/jsobj.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 507 - (hide annotations)
Sun Jan 10 07:23:34 2010 UTC (10 years, 8 months ago) by siliconforks
File size: 196791 byte(s)
Update SpiderMonkey from Firefox 3.6rc1.

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 332 indirectCall = (caller && caller->regs && *caller->regs->pc != JSOP_EVAL);
1261 siliconforks 507 uintN staticLevel = caller->script->staticLevel + 1;
1262 siliconforks 332
1263     /*
1264 siliconforks 460 * This call to js_GetWrappedObject is safe because of the security checks
1265     * we do below. However, the control flow below is confusing, so we double
1266     * check. There are two cases:
1267     * - Direct call: This object is never used. So unwrapping can't hurt.
1268     * - Indirect call: If this object isn't already the scope chain (which
1269     * we're guaranteed to be allowed to access) then we do a security
1270     * check.
1271     */
1272     obj = js_GetWrappedObject(cx, obj);
1273    
1274     /*
1275 siliconforks 332 * Ban all indirect uses of eval (global.foo = eval; global.foo(...)) and
1276     * calls that attempt to use a non-global object as the "with" object in
1277     * the former indirect case.
1278     */
1279 siliconforks 460 {
1280     JSObject *parent = OBJ_GET_PARENT(cx, obj);
1281     if (indirectCall || parent) {
1282     uintN flags = parent
1283     ? JSREPORT_ERROR
1284     : JSREPORT_STRICT | JSREPORT_WARNING;
1285     if (!JS_ReportErrorFlagsAndNumber(cx, flags, js_GetErrorMessage, NULL,
1286     JSMSG_BAD_INDIRECT_CALL,
1287     js_eval_str)) {
1288     return JS_FALSE;
1289     }
1290 siliconforks 332 }
1291     }
1292    
1293     if (!JSVAL_IS_STRING(argv[0])) {
1294     *rval = argv[0];
1295     return JS_TRUE;
1296     }
1297    
1298     /*
1299     * If the caller is a lightweight function and doesn't have a variables
1300     * object, then we need to provide one for the compiler to stick any
1301     * declared (var) variables into.
1302     */
1303 siliconforks 460 if (caller && !caller->varobj && !js_GetCallObject(cx, caller))
1304 siliconforks 332 return JS_FALSE;
1305    
1306 siliconforks 460 /* Accept an optional trailing argument that overrides the scope object. */
1307     JSObject *scopeobj = NULL;
1308     if (argc >= 2) {
1309     if (!js_ValueToObject(cx, argv[1], &scopeobj))
1310     return JS_FALSE;
1311     argv[1] = OBJECT_TO_JSVAL(scopeobj);
1312 siliconforks 332 }
1313    
1314     /* From here on, control must exit through label out with ok set. */
1315     MUST_FLOW_THROUGH("out");
1316     if (!scopeobj) {
1317     #if JS_HAS_EVAL_THIS_SCOPE
1318     /* If obj.eval(str), emulate 'with (obj) eval(str)' in the caller. */
1319     if (indirectCall) {
1320     callerScopeChain = js_GetScopeChain(cx, caller);
1321     if (!callerScopeChain) {
1322     ok = JS_FALSE;
1323     goto out;
1324     }
1325     OBJ_TO_INNER_OBJECT(cx, obj);
1326     if (!obj) {
1327     ok = JS_FALSE;
1328     goto out;
1329     }
1330     if (obj != callerScopeChain) {
1331     ok = js_CheckPrincipalsAccess(cx, obj,
1332 siliconforks 460 JS_StackFramePrincipals(cx, caller),
1333 siliconforks 332 cx->runtime->atomState.evalAtom);
1334     if (!ok)
1335     goto out;
1336    
1337     scopeobj = js_NewWithObject(cx, obj, callerScopeChain, -1);
1338     if (!scopeobj) {
1339     ok = JS_FALSE;
1340     goto out;
1341     }
1342    
1343     /* Set fp->scopeChain too, for the compiler. */
1344     caller->scopeChain = fp->scopeChain = scopeobj;
1345    
1346     /* Remember scopeobj so we can null its private when done. */
1347     setCallerScopeChain = scopeobj;
1348     }
1349    
1350     callerVarObj = caller->varobj;
1351     if (obj != callerVarObj) {
1352     /* Set fp->varobj too, for the compiler. */
1353     caller->varobj = fp->varobj = obj;
1354     setCallerVarObj = JS_TRUE;
1355     }
1356     }
1357     #endif
1358    
1359     /*
1360     * Compile using caller's current scope object.
1361     *
1362     * NB: This means that native callers (who reach this point through
1363     * the C API) must use the two parameter form.
1364     */
1365     if (caller) {
1366     scopeobj = js_GetScopeChain(cx, caller);
1367     if (!scopeobj) {
1368     ok = JS_FALSE;
1369     goto out;
1370     }
1371     }
1372 siliconforks 460 } else {
1373     scopeobj = js_GetWrappedObject(cx, scopeobj);
1374     OBJ_TO_INNER_OBJECT(cx, scopeobj);
1375     if (!scopeobj) {
1376     ok = JS_FALSE;
1377     goto out;
1378     }
1379     ok = js_CheckPrincipalsAccess(cx, scopeobj,
1380     JS_StackFramePrincipals(cx, caller),
1381     cx->runtime->atomState.evalAtom);
1382     if (!ok)
1383     goto out;
1384    
1385     scopeobj = js_NewWithObject(cx, scopeobj,
1386     JS_GetGlobalForObject(cx, scopeobj), -1);
1387     if (!scopeobj) {
1388     ok = JS_FALSE;
1389     goto out;
1390     }
1391     argv[1] = OBJECT_TO_JSVAL(scopeobj);
1392 siliconforks 332 }
1393    
1394     /* Ensure we compile this eval with the right object in the scope chain. */
1395     scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_eval_str);
1396     if (!scopeobj) {
1397     ok = JS_FALSE;
1398     goto out;
1399     }
1400    
1401 siliconforks 460 tcflags = TCF_COMPILE_N_GO;
1402 siliconforks 332 if (caller) {
1403 siliconforks 507 tcflags |= TCF_PUT_STATIC_LEVEL(staticLevel);
1404 siliconforks 332 principals = JS_EvalFramePrincipals(cx, fp, caller);
1405     file = js_ComputeFilename(cx, caller, principals, &line);
1406     } else {
1407 siliconforks 460 principals = NULL;
1408 siliconforks 332 file = NULL;
1409     line = 0;
1410     }
1411    
1412 siliconforks 460 str = JSVAL_TO_STRING(argv[0]);
1413     script = NULL;
1414    
1415     /* Cache local eval scripts indexed by source qualified by scope. */
1416     bucket = EvalCacheHash(cx, str);
1417 siliconforks 507 if (!indirectCall && argc == 1 && caller->fun) {
1418 siliconforks 460 uintN count = 0;
1419     JSScript **scriptp = bucket;
1420    
1421     EVAL_CACHE_METER(probe);
1422     while ((script = *scriptp) != NULL) {
1423     if ((script->flags & JSSF_SAVED_CALLER_FUN) &&
1424 siliconforks 507 script->staticLevel == staticLevel &&
1425 siliconforks 460 script->version == cx->version &&
1426     (script->principals == principals ||
1427     (principals->subsume(principals, script->principals) &&
1428     script->principals->subsume(script->principals, principals)))) {
1429     /*
1430     * Get the prior (cache-filling) eval's saved caller function.
1431     * See JSCompiler::compileScript in jsparse.cpp.
1432     */
1433     JSFunction *fun;
1434 siliconforks 507 fun = script->getFunction(0);
1435 siliconforks 460
1436     if (fun == caller->fun) {
1437     /*
1438     * Get the source string passed for safekeeping in the
1439     * atom map by the prior eval to JSCompiler::compileScript.
1440     */
1441     JSString *src = ATOM_TO_STRING(script->atomMap.vector[0]);
1442    
1443     if (src == str || js_EqualStrings(src, str)) {
1444     /*
1445     * Source matches, qualify by comparing scopeobj to the
1446     * COMPILE_N_GO-memoized parent of the first literal
1447     * function or regexp object if any. If none, then this
1448     * script has no compiled-in dependencies on the prior
1449     * eval's scopeobj.
1450     */
1451 siliconforks 507 JSObjectArray *objarray = script->objects();
1452 siliconforks 460 int i = 1;
1453     if (objarray->length == 1) {
1454     if (script->regexpsOffset != 0) {
1455 siliconforks 507 objarray = script->regexps();
1456 siliconforks 460 i = 0;
1457     } else {
1458     EVAL_CACHE_METER(noscope);
1459     i = -1;
1460     }
1461     }
1462     if (i < 0 ||
1463     STOBJ_GET_PARENT(objarray->vector[i]) == scopeobj) {
1464 siliconforks 507 JS_ASSERT(staticLevel == script->staticLevel);
1465 siliconforks 460 EVAL_CACHE_METER(hit);
1466     *scriptp = script->u.nextToGC;
1467     script->u.nextToGC = NULL;
1468     break;
1469     }
1470     }
1471     }
1472     }
1473    
1474     if (++count == EVAL_CACHE_CHAIN_LIMIT) {
1475     script = NULL;
1476     break;
1477     }
1478     EVAL_CACHE_METER(step);
1479     scriptp = &script->u.nextToGC;
1480     }
1481     }
1482    
1483 siliconforks 332 if (!script) {
1484 siliconforks 460 script = JSCompiler::compileScript(cx, scopeobj, caller, principals, tcflags,
1485 siliconforks 507 str->chars(), str->length(),
1486 siliconforks 460 NULL, file, line, str);
1487     if (!script) {
1488     ok = JS_FALSE;
1489     goto out;
1490     }
1491 siliconforks 332 }
1492    
1493     if (argc < 2) {
1494     /* Execute using caller's new scope object (might be a Call object). */
1495     if (caller)
1496     scopeobj = caller->scopeChain;
1497     }
1498    
1499     /*
1500     * Belt-and-braces: check that the lesser of eval's principals and the
1501     * caller's principals has access to scopeobj.
1502     */
1503     ok = js_CheckPrincipalsAccess(cx, scopeobj, principals,
1504     cx->runtime->atomState.evalAtom);
1505     if (ok)
1506     ok = js_Execute(cx, scopeobj, script, caller, JSFRAME_EVAL, rval);
1507    
1508 siliconforks 460 script->u.nextToGC = *bucket;
1509     *bucket = script;
1510 siliconforks 332 #ifdef CHECK_SCRIPT_OWNER
1511     script->owner = NULL;
1512     #endif
1513    
1514     out:
1515     #if JS_HAS_EVAL_THIS_SCOPE
1516     /* Restore OBJ_GET_PARENT(scopeobj) not callerScopeChain in case of Call. */
1517     if (setCallerScopeChain) {
1518     caller->scopeChain = callerScopeChain;
1519     JS_ASSERT(OBJ_GET_CLASS(cx, setCallerScopeChain) == &js_WithClass);
1520 siliconforks 507 setCallerScopeChain->setPrivate(NULL);
1521 siliconforks 332 }
1522     if (setCallerVarObj)
1523     caller->varobj = callerVarObj;
1524     #endif
1525     return ok;
1526     }
1527    
1528     #if JS_HAS_OBJ_WATCHPOINT
1529    
1530     static JSBool
1531     obj_watch_handler(JSContext *cx, JSObject *obj, jsval id, jsval old, jsval *nvp,
1532     void *closure)
1533     {
1534     JSObject *callable;
1535     JSSecurityCallbacks *callbacks;
1536     JSStackFrame *caller;
1537     JSPrincipals *subject, *watcher;
1538     JSResolvingKey key;
1539     JSResolvingEntry *entry;
1540     uint32 generation;
1541     jsval argv[3];
1542     JSBool ok;
1543    
1544     callable = (JSObject *) closure;
1545    
1546     callbacks = JS_GetSecurityCallbacks(cx);
1547     if (callbacks && callbacks->findObjectPrincipals) {
1548     /* Skip over any obj_watch_* frames between us and the real subject. */
1549 siliconforks 460 caller = js_GetScriptedCaller(cx, NULL);
1550 siliconforks 332 if (caller) {
1551     /*
1552     * Only call the watch handler if the watcher is allowed to watch
1553     * the currently executing script.
1554     */
1555     watcher = callbacks->findObjectPrincipals(cx, callable);
1556     subject = JS_StackFramePrincipals(cx, caller);
1557    
1558     if (watcher && subject && !watcher->subsume(watcher, subject)) {
1559     /* Silently don't call the watch handler. */
1560     return JS_TRUE;
1561     }
1562     }
1563     }
1564    
1565     /* Avoid recursion on (obj, id) already being watched on cx. */
1566     key.obj = obj;
1567     key.id = id;
1568     if (!js_StartResolving(cx, &key, JSRESFLAG_WATCH, &entry))
1569     return JS_FALSE;
1570     if (!entry)
1571     return JS_TRUE;
1572     generation = cx->resolvingTable->generation;
1573    
1574     argv[0] = id;
1575     argv[1] = old;
1576     argv[2] = *nvp;
1577     ok = js_InternalCall(cx, obj, OBJECT_TO_JSVAL(callable), 3, argv, nvp);
1578     js_StopResolving(cx, &key, JSRESFLAG_WATCH, entry, generation);
1579     return ok;
1580     }
1581    
1582     static JSBool
1583     obj_watch(JSContext *cx, uintN argc, jsval *vp)
1584     {
1585     JSObject *callable;
1586     jsval userid, value;
1587     jsid propid;
1588     JSObject *obj;
1589     uintN attrs;
1590    
1591     if (argc <= 1) {
1592     js_ReportMissingArg(cx, vp, 1);
1593     return JS_FALSE;
1594     }
1595    
1596     callable = js_ValueToCallableObject(cx, &vp[3], 0);
1597     if (!callable)
1598     return JS_FALSE;
1599    
1600     /* Compute the unique int/atom symbol id needed by js_LookupProperty. */
1601     userid = vp[2];
1602     if (!JS_ValueToId(cx, userid, &propid))
1603     return JS_FALSE;
1604    
1605     obj = JS_THIS_OBJECT(cx, vp);
1606 siliconforks 507 if (!obj || !obj->checkAccess(cx, propid, JSACC_WATCH, &value, &attrs))
1607 siliconforks 332 return JS_FALSE;
1608     if (attrs & JSPROP_READONLY)
1609     return JS_TRUE;
1610     *vp = JSVAL_VOID;
1611    
1612     if (OBJ_IS_DENSE_ARRAY(cx, obj) && !js_MakeArraySlow(cx, obj))
1613     return JS_FALSE;
1614     return JS_SetWatchPoint(cx, obj, userid, obj_watch_handler, callable);
1615     }
1616    
1617     static JSBool
1618     obj_unwatch(JSContext *cx, uintN argc, jsval *vp)
1619     {
1620     JSObject *obj;
1621    
1622     obj = JS_THIS_OBJECT(cx, vp);
1623     if (!obj)
1624     return JS_FALSE;
1625     *vp = JSVAL_VOID;
1626     return JS_ClearWatchPoint(cx, obj, argc != 0 ? vp[2] : JSVAL_VOID,
1627     NULL, NULL);
1628     }
1629    
1630     #endif /* JS_HAS_OBJ_WATCHPOINT */
1631    
1632     /*
1633     * Prototype and property query methods, to complement the 'in' and
1634     * 'instanceof' operators.
1635     */
1636    
1637     /* Proposed ECMA 15.2.4.5. */
1638 siliconforks 399 static JSBool
1639     obj_hasOwnProperty(JSContext *cx, uintN argc, jsval *vp)
1640 siliconforks 332 {
1641     JSObject *obj;
1642    
1643     obj = JS_THIS_OBJECT(cx, vp);
1644     return obj &&
1645     js_HasOwnPropertyHelper(cx, obj->map->ops->lookupProperty, argc, vp);
1646     }
1647    
1648     JSBool
1649     js_HasOwnPropertyHelper(JSContext *cx, JSLookupPropOp lookup, uintN argc,
1650     jsval *vp)
1651     {
1652     jsid id;
1653     JSObject *obj;
1654    
1655     if (!JS_ValueToId(cx, argc != 0 ? vp[2] : JSVAL_VOID, &id))
1656     return JS_FALSE;
1657     obj = JS_THIS_OBJECT(cx, vp);
1658     return obj && js_HasOwnProperty(cx, lookup, obj, id, vp);
1659     }
1660    
1661     JSBool
1662     js_HasOwnProperty(JSContext *cx, JSLookupPropOp lookup, JSObject *obj, jsid id,
1663     jsval *vp)
1664     {
1665     JSObject *obj2;
1666     JSProperty *prop;
1667     JSScopeProperty *sprop;
1668    
1669     if (!lookup(cx, obj, id, &obj2, &prop))
1670     return JS_FALSE;
1671     if (!prop) {
1672     *vp = JSVAL_FALSE;
1673     } else if (obj2 == obj) {
1674     *vp = JSVAL_TRUE;
1675     } else {
1676     JSClass *clasp;
1677     JSExtendedClass *xclasp;
1678     JSObject *outer;
1679    
1680     clasp = OBJ_GET_CLASS(cx, obj2);
1681     if (!(clasp->flags & JSCLASS_IS_EXTENDED) ||
1682     !(xclasp = (JSExtendedClass *) clasp)->outerObject) {
1683     outer = NULL;
1684     } else {
1685     outer = xclasp->outerObject(cx, obj2);
1686     if (!outer)
1687     return JS_FALSE;
1688     }
1689     if (outer == obj) {
1690     *vp = JSVAL_TRUE;
1691     } else if (OBJ_IS_NATIVE(obj2) && OBJ_GET_CLASS(cx, obj) == clasp) {
1692     /*
1693     * The combination of JSPROP_SHARED and JSPROP_PERMANENT in a
1694     * delegated property makes that property appear to be direct in
1695     * all delegating instances of the same native class. This hack
1696     * avoids bloating every function instance with its own 'length'
1697     * (AKA 'arity') property. But it must not extend across class
1698     * boundaries, to avoid making hasOwnProperty lie (bug 320854).
1699     *
1700     * It's not really a hack, of course: a permanent property can't
1701     * be deleted, and JSPROP_SHARED means "don't allocate a slot in
1702     * any instance, prototype or delegating". Without a slot, and
1703     * without the ability to remove and recreate (with differences)
1704     * the property, there is no way to tell whether it is directly
1705     * owned, or indirectly delegated.
1706     */
1707     sprop = (JSScopeProperty *)prop;
1708     *vp = BOOLEAN_TO_JSVAL(SPROP_IS_SHARED_PERMANENT(sprop));
1709     } else {
1710     *vp = JSVAL_FALSE;
1711     }
1712     }
1713     if (prop)
1714 siliconforks 507 obj2->dropProperty(cx, prop);
1715 siliconforks 332 return JS_TRUE;
1716     }
1717    
1718 siliconforks 399 #ifdef JS_TRACER
1719 siliconforks 460 static JSBool FASTCALL
1720 siliconforks 399 Object_p_hasOwnProperty(JSContext* cx, JSObject* obj, JSString *str)
1721     {
1722     jsid id;
1723     jsval v;
1724    
1725 siliconforks 460 if (!js_ValueToStringId(cx, STRING_TO_JSVAL(str), &id) ||
1726     !js_HasOwnProperty(cx, obj->map->ops->lookupProperty, obj, id, &v)) {
1727     js_SetBuiltinError(cx);
1728 siliconforks 399 return JSVAL_TO_BOOLEAN(JSVAL_VOID);
1729 siliconforks 460 }
1730    
1731 siliconforks 399 JS_ASSERT(JSVAL_IS_BOOLEAN(v));
1732     return JSVAL_TO_BOOLEAN(v);
1733     }
1734     #endif
1735    
1736 siliconforks 332 /* Proposed ECMA 15.2.4.6. */
1737     static JSBool
1738     obj_isPrototypeOf(JSContext *cx, uintN argc, jsval *vp)
1739     {
1740     JSBool b;
1741    
1742     if (!js_IsDelegate(cx, JS_THIS_OBJECT(cx, vp),
1743     argc != 0 ? vp[2] : JSVAL_VOID, &b)) {
1744     return JS_FALSE;
1745     }
1746     *vp = BOOLEAN_TO_JSVAL(b);
1747     return JS_TRUE;
1748     }
1749    
1750     /* Proposed ECMA 15.2.4.7. */
1751 siliconforks 399 static JSBool
1752     obj_propertyIsEnumerable(JSContext *cx, uintN argc, jsval *vp)
1753 siliconforks 332 {
1754     jsid id;
1755     JSObject *obj;
1756    
1757     if (!JS_ValueToId(cx, argc != 0 ? vp[2] : JSVAL_VOID, &id))
1758     return JS_FALSE;
1759    
1760     obj = JS_THIS_OBJECT(cx, vp);
1761     return obj && js_PropertyIsEnumerable(cx, obj, id, vp);
1762     }
1763    
1764 siliconforks 399 #ifdef JS_TRACER
1765 siliconforks 460 static JSBool FASTCALL
1766 siliconforks 399 Object_p_propertyIsEnumerable(JSContext* cx, JSObject* obj, JSString *str)
1767     {
1768     jsid id = ATOM_TO_JSID(STRING_TO_JSVAL(str));
1769     jsval v;
1770 siliconforks 460
1771     if (!js_PropertyIsEnumerable(cx, obj, id, &v)) {
1772     js_SetBuiltinError(cx);
1773 siliconforks 399 return JSVAL_TO_BOOLEAN(JSVAL_VOID);
1774 siliconforks 460 }
1775    
1776 siliconforks 399 JS_ASSERT(JSVAL_IS_BOOLEAN(v));
1777     return JSVAL_TO_BOOLEAN(v);
1778     }
1779     #endif
1780    
1781 siliconforks 332 JSBool
1782     js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
1783     {
1784     JSObject *pobj;
1785     uintN attrs;
1786     JSProperty *prop;
1787     JSBool ok;
1788    
1789 siliconforks 507 if (!obj->lookupProperty(cx, id, &pobj, &prop))
1790 siliconforks 332 return JS_FALSE;
1791    
1792     if (!prop) {
1793     *vp = JSVAL_FALSE;
1794     return JS_TRUE;
1795     }
1796    
1797     /*
1798     * XXX ECMA spec error compatible: return false unless hasOwnProperty.
1799     * The ECMA spec really should be fixed so propertyIsEnumerable and the
1800     * for..in loop agree on whether prototype properties are enumerable,
1801     * obviously by fixing this method (not by breaking the for..in loop!).
1802     *
1803     * We check here for shared permanent prototype properties, which should
1804     * be treated as if they are local to obj. They are an implementation
1805     * technique used to satisfy ECMA requirements; users should not be able
1806     * to distinguish a shared permanent proto-property from a local one.
1807     */
1808     if (pobj != obj &&
1809     !(OBJ_IS_NATIVE(pobj) &&
1810     SPROP_IS_SHARED_PERMANENT((JSScopeProperty *)prop))) {
1811 siliconforks 507 pobj->dropProperty(cx, prop);
1812 siliconforks 332 *vp = JSVAL_FALSE;
1813     return JS_TRUE;
1814     }
1815    
1816 siliconforks 507 ok = pobj->getAttributes(cx, id, prop, &attrs);
1817     pobj->dropProperty(cx, prop);
1818 siliconforks 332 if (ok)
1819     *vp = BOOLEAN_TO_JSVAL((attrs & JSPROP_ENUMERATE) != 0);
1820     return ok;
1821     }
1822    
1823     #if JS_HAS_GETTER_SETTER
1824 siliconforks 460 JS_FRIEND_API(JSBool)
1825     js_obj_defineGetter(JSContext *cx, uintN argc, jsval *vp)
1826 siliconforks 332 {
1827     jsval fval, junk;
1828     jsid id;
1829     JSObject *obj;
1830     uintN attrs;
1831    
1832     if (argc <= 1 || JS_TypeOfValue(cx, vp[3]) != JSTYPE_FUNCTION) {
1833     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1834     JSMSG_BAD_GETTER_OR_SETTER,
1835     js_getter_str);
1836     return JS_FALSE;
1837     }
1838     fval = vp[3];
1839    
1840     if (!JS_ValueToId(cx, vp[2], &id))
1841     return JS_FALSE;
1842     obj = JS_THIS_OBJECT(cx, vp);
1843     if (!obj || !js_CheckRedeclaration(cx, obj, id, JSPROP_GETTER, NULL, NULL))
1844     return JS_FALSE;
1845     /*
1846     * Getters and setters are just like watchpoints from an access
1847     * control point of view.
1848     */
1849 siliconforks 507 if (!obj->checkAccess(cx, id, JSACC_WATCH, &junk, &attrs))
1850 siliconforks 332 return JS_FALSE;
1851     *vp = JSVAL_VOID;
1852 siliconforks 507 return obj->defineProperty(cx, id, JSVAL_VOID,
1853     js_CastAsPropertyOp(JSVAL_TO_OBJECT(fval)), JS_PropertyStub,
1854     JSPROP_ENUMERATE | JSPROP_GETTER | JSPROP_SHARED);
1855 siliconforks 332 }
1856    
1857 siliconforks 460 JS_FRIEND_API(JSBool)
1858     js_obj_defineSetter(JSContext *cx, uintN argc, jsval *vp)
1859 siliconforks 332 {
1860     jsval fval, junk;
1861     jsid id;
1862     JSObject *obj;
1863     uintN attrs;
1864    
1865     if (argc <= 1 || JS_TypeOfValue(cx, vp[3]) != JSTYPE_FUNCTION) {
1866     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1867     JSMSG_BAD_GETTER_OR_SETTER,
1868     js_setter_str);
1869     return JS_FALSE;
1870     }
1871     fval = vp[3];
1872    
1873     if (!JS_ValueToId(cx, vp[2], &id))
1874     return JS_FALSE;
1875     obj = JS_THIS_OBJECT(cx, vp);
1876     if (!obj || !js_CheckRedeclaration(cx, obj, id, JSPROP_SETTER, NULL, NULL))
1877     return JS_FALSE;
1878     /*
1879     * Getters and setters are just like watchpoints from an access
1880     * control point of view.
1881     */
1882 siliconforks 507 if (!obj->checkAccess(cx, id, JSACC_WATCH, &junk, &attrs))
1883 siliconforks 332 return JS_FALSE;
1884     *vp = JSVAL_VOID;
1885 siliconforks 507 return obj->defineProperty(cx, id, JSVAL_VOID,
1886     JS_PropertyStub, js_CastAsPropertyOp(JSVAL_TO_OBJECT(fval)),
1887     JSPROP_ENUMERATE | JSPROP_SETTER | JSPROP_SHARED);
1888 siliconforks 332 }
1889    
1890     static JSBool
1891     obj_lookupGetter(JSContext *cx, uintN argc, jsval *vp)
1892     {
1893     jsid id;
1894     JSObject *obj, *pobj;
1895     JSProperty *prop;
1896     JSScopeProperty *sprop;
1897    
1898     if (!JS_ValueToId(cx, argc != 0 ? vp[2] : JSVAL_VOID, &id))
1899     return JS_FALSE;
1900     obj = JS_THIS_OBJECT(cx, vp);
1901 siliconforks 507 if (!obj || !obj->lookupProperty(cx, id, &pobj, &prop))
1902 siliconforks 332 return JS_FALSE;
1903     *vp = JSVAL_VOID;
1904     if (prop) {
1905     if (OBJ_IS_NATIVE(pobj)) {
1906     sprop = (JSScopeProperty *) prop;
1907     if (sprop->attrs & JSPROP_GETTER)
1908 siliconforks 460 *vp = js_CastAsObjectJSVal(sprop->getter);
1909 siliconforks 332 }
1910 siliconforks 507 pobj->dropProperty(cx, prop);
1911 siliconforks 332 }
1912     return JS_TRUE;
1913     }
1914    
1915     static JSBool
1916     obj_lookupSetter(JSContext *cx, uintN argc, jsval *vp)
1917     {
1918     jsid id;
1919     JSObject *obj, *pobj;
1920     JSProperty *prop;
1921     JSScopeProperty *sprop;
1922    
1923     if (!JS_ValueToId(cx, argc != 0 ? vp[2] : JSVAL_VOID, &id))
1924     return JS_FALSE;
1925     obj = JS_THIS_OBJECT(cx, vp);
1926 siliconforks 507 if (!obj || !obj->lookupProperty(cx, id, &pobj, &prop))
1927 siliconforks 332 return JS_FALSE;
1928     *vp = JSVAL_VOID;
1929     if (prop) {
1930     if (OBJ_IS_NATIVE(pobj)) {
1931     sprop = (JSScopeProperty *) prop;
1932     if (sprop->attrs & JSPROP_SETTER)
1933 siliconforks 460 *vp = js_CastAsObjectJSVal(sprop->setter);
1934 siliconforks 332 }
1935 siliconforks 507 pobj->dropProperty(cx, prop);
1936 siliconforks 332 }
1937     return JS_TRUE;
1938     }
1939     #endif /* JS_HAS_GETTER_SETTER */
1940    
1941     JSBool
1942     obj_getPrototypeOf(JSContext *cx, uintN argc, jsval *vp)
1943     {
1944     JSObject *obj;
1945     uintN attrs;
1946    
1947     if (argc == 0) {
1948     js_ReportMissingArg(cx, vp, 0);
1949     return JS_FALSE;
1950     }
1951    
1952     obj = js_ValueToNonNullObject(cx, vp[2]);
1953     if (!obj)
1954     return JS_FALSE;
1955     vp[2] = OBJECT_TO_JSVAL(obj);
1956    
1957 siliconforks 507 return obj->checkAccess(cx, ATOM_TO_JSID(cx->runtime->atomState.protoAtom),
1958 siliconforks 332 JSACC_PROTO, vp, &attrs);
1959     }
1960    
1961     #if JS_HAS_OBJ_WATCHPOINT
1962     const char js_watch_str[] = "watch";
1963     const char js_unwatch_str[] = "unwatch";
1964     #endif
1965     const char js_hasOwnProperty_str[] = "hasOwnProperty";
1966     const char js_isPrototypeOf_str[] = "isPrototypeOf";
1967     const char js_propertyIsEnumerable_str[] = "propertyIsEnumerable";
1968     #if JS_HAS_GETTER_SETTER
1969     const char js_defineGetter_str[] = "__defineGetter__";
1970     const char js_defineSetter_str[] = "__defineSetter__";
1971     const char js_lookupGetter_str[] = "__lookupGetter__";
1972     const char js_lookupSetter_str[] = "__lookupSetter__";
1973     #endif
1974    
1975 siliconforks 460 JS_DEFINE_TRCINFO_1(obj_valueOf,
1976     (3, (static, JSVAL, Object_p_valueOf, CONTEXT, THIS, STRING, 0, 0)))
1977 siliconforks 399 JS_DEFINE_TRCINFO_1(obj_hasOwnProperty,
1978 siliconforks 460 (3, (static, BOOL_FAIL, Object_p_hasOwnProperty, CONTEXT, THIS, STRING, 0, 0)))
1979 siliconforks 399 JS_DEFINE_TRCINFO_1(obj_propertyIsEnumerable,
1980 siliconforks 460 (3, (static, BOOL_FAIL, Object_p_propertyIsEnumerable, CONTEXT, THIS, STRING, 0, 0)))
1981 siliconforks 399
1982 siliconforks 332 static JSFunctionSpec object_methods[] = {
1983     #if JS_HAS_TOSOURCE
1984     JS_FN(js_toSource_str, obj_toSource, 0,0),
1985     #endif
1986     JS_FN(js_toString_str, obj_toString, 0,0),
1987     JS_FN(js_toLocaleString_str, obj_toLocaleString, 0,0),
1988 siliconforks 507 JS_TN(js_valueOf_str, obj_valueOf, 0,0, &obj_valueOf_trcinfo),
1989 siliconforks 332 #if JS_HAS_OBJ_WATCHPOINT
1990     JS_FN(js_watch_str, obj_watch, 2,0),
1991     JS_FN(js_unwatch_str, obj_unwatch, 1,0),
1992     #endif
1993 siliconforks 507 JS_TN(js_hasOwnProperty_str, obj_hasOwnProperty, 1,0, &obj_hasOwnProperty_trcinfo),
1994 siliconforks 332 JS_FN(js_isPrototypeOf_str, obj_isPrototypeOf, 1,0),
1995 siliconforks 507 JS_TN(js_propertyIsEnumerable_str, obj_propertyIsEnumerable, 1,0, &obj_propertyIsEnumerable_trcinfo),
1996 siliconforks 332 #if JS_HAS_GETTER_SETTER
1997 siliconforks 460 JS_FN(js_defineGetter_str, js_obj_defineGetter, 2,0),
1998     JS_FN(js_defineSetter_str, js_obj_defineSetter, 2,0),
1999 siliconforks 332 JS_FN(js_lookupGetter_str, obj_lookupGetter, 1,0),
2000     JS_FN(js_lookupSetter_str, obj_lookupSetter, 1,0),
2001     #endif
2002     JS_FS_END
2003     };
2004    
2005     static JSFunctionSpec object_static_methods[] = {
2006 siliconforks 399 JS_FN("getPrototypeOf", obj_getPrototypeOf, 1,0),
2007 siliconforks 332 JS_FS_END
2008     };
2009    
2010 siliconforks 507 static bool
2011     AllocSlots(JSContext *cx, JSObject *obj, size_t nslots);
2012    
2013     static inline bool
2014     InitScopeForObject(JSContext* cx, JSObject* obj, JSObject* proto, JSObjectOps* ops)
2015     {
2016     JS_ASSERT(OPS_IS_NATIVE(ops));
2017     JS_ASSERT(proto == OBJ_GET_PROTO(cx, obj));
2018    
2019     /* Share proto's emptyScope only if obj is similar to proto. */
2020     JSClass *clasp = OBJ_GET_CLASS(cx, obj);
2021     JSScope *scope;
2022     if (proto && OBJ_IS_NATIVE(proto) &&
2023     (scope = OBJ_SCOPE(proto))->canProvideEmptyScope(ops, clasp)) {
2024     scope = scope->getEmptyScope(cx, clasp);
2025     if (!scope)
2026     goto bad;
2027     } else {
2028     scope = JSScope::create(cx, ops, clasp, obj, js_GenerateShape(cx, false));
2029     if (!scope)
2030     goto bad;
2031    
2032     /* Let JSScope::create set freeslot so as to reserve slots. */
2033     JS_ASSERT(scope->freeslot >= JSSLOT_PRIVATE);
2034     if (scope->freeslot > JS_INITIAL_NSLOTS &&
2035     !AllocSlots(cx, obj, scope->freeslot)) {
2036     JSScope::destroy(cx, scope);
2037     goto bad;
2038     }
2039     }
2040     obj->map = scope;
2041     return true;
2042    
2043     bad:
2044     /* The GC nulls map initially. It should still be null on error. */
2045     JS_ASSERT(!obj->map);
2046     return false;
2047     }
2048    
2049     JSObject *
2050     js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
2051     JSObject *parent, size_t objectSize)
2052     {
2053     #ifdef INCLUDE_MOZILLA_DTRACE
2054     if (JAVASCRIPT_OBJECT_CREATE_START_ENABLED())
2055     jsdtrace_object_create_start(cx->fp, clasp);
2056     #endif
2057    
2058     /* Assert that the class is a proper class. */
2059     JS_ASSERT_IF(clasp->flags & JSCLASS_IS_EXTENDED,
2060     ((JSExtendedClass *)clasp)->equality);
2061    
2062     /* Always call the class's getObjectOps hook if it has one. */
2063     JSObjectOps *ops = clasp->getObjectOps
2064     ? clasp->getObjectOps(cx, clasp)
2065     : &js_ObjectOps;
2066    
2067     /*
2068     * Allocate an object from the GC heap and initialize all its fields before
2069     * doing any operation that can potentially trigger GC. Functions have a
2070     * larger non-standard allocation size.
2071     */
2072     JSObject* obj;
2073     if (clasp == &js_FunctionClass && !objectSize) {
2074     obj = (JSObject*) js_NewGCFunction(cx, GCX_OBJECT);
2075     #ifdef DEBUG
2076     memset((uint8 *) obj + sizeof(JSObject), JS_FREE_PATTERN,
2077     sizeof(JSFunction) - sizeof(JSObject));
2078     #endif
2079     } else {
2080     JS_ASSERT(!objectSize || objectSize == sizeof(JSObject));
2081     obj = js_NewGCObject(cx, GCX_OBJECT);
2082     }
2083     if (!obj)
2084     goto out;
2085    
2086     /*
2087     * Default parent to the parent of the prototype, which was set from
2088     * the parent of the prototype's constructor.
2089     */
2090     obj->init(clasp,
2091     proto,
2092     (!parent && proto) ? proto->getParent() : parent,
2093     JSObject::defaultPrivate(clasp));
2094    
2095     if (OPS_IS_NATIVE(ops)) {
2096     if (!InitScopeForObject(cx, obj, proto, ops)) {
2097     obj = NULL;
2098     goto out;
2099     }
2100     } else {
2101     JS_ASSERT(ops->objectMap->ops == ops);
2102     obj->map = const_cast<JSObjectMap *>(ops->objectMap);
2103     }
2104    
2105     /* Check that the newborn root still holds the object. */
2106     JS_ASSERT_IF(!cx->localRootStack, cx->weakRoots.newborn[GCX_OBJECT] == obj);
2107    
2108     /*
2109     * Do not call debug hooks on trace, because we might be in a non-_FAIL
2110     * builtin. See bug 481444.
2111     */
2112     if (cx->debugHooks->objectHook && !JS_ON_TRACE(cx)) {
2113     JSAutoTempValueRooter tvr(cx, obj);
2114     JS_KEEP_ATOMS(cx->runtime);
2115     cx->debugHooks->objectHook(cx, obj, JS_TRUE,
2116     cx->debugHooks->objectHookData);
2117     JS_UNKEEP_ATOMS(cx->runtime);
2118     cx->weakRoots.newborn[GCX_OBJECT] = obj;
2119     }
2120    
2121     out:
2122     #ifdef INCLUDE_MOZILLA_DTRACE
2123     if (JAVASCRIPT_OBJECT_CREATE_ENABLED())
2124     jsdtrace_object_create(cx, clasp, obj);
2125     if (JAVASCRIPT_OBJECT_CREATE_DONE_ENABLED())
2126     jsdtrace_object_create_done(cx->fp, clasp);
2127     #endif
2128     return obj;
2129     }
2130    
2131     JSObject *
2132     js_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto,
2133     JSObject *parent, size_t objectSize)
2134     {
2135     jsid id;
2136    
2137     /* Bootstrap the ur-object, and make it the default prototype object. */
2138     if (!proto) {
2139     if (!js_GetClassId(cx, clasp, &id))
2140     return NULL;
2141     if (!js_GetClassPrototype(cx, parent, id, &proto))
2142     return NULL;
2143     if (!proto &&
2144     !js_GetClassPrototype(cx, parent, INT_TO_JSID(JSProto_Object),
2145     &proto)) {
2146     return NULL;
2147     }
2148     }
2149    
2150     return js_NewObjectWithGivenProto(cx, clasp, proto, parent, objectSize);
2151     }
2152    
2153 siliconforks 332 JSBool
2154     js_Object(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2155     {
2156     if (argc == 0) {
2157     /* Trigger logic below to construct a blank object. */
2158     obj = NULL;
2159     } else {
2160     /* If argv[0] is null or undefined, obj comes back null. */
2161     if (!js_ValueToObject(cx, argv[0], &obj))
2162     return JS_FALSE;
2163     }
2164     if (!obj) {
2165     JS_ASSERT(!argc || JSVAL_IS_NULL(argv[0]) || JSVAL_IS_VOID(argv[0]));
2166 siliconforks 460 if (JS_IsConstructing(cx))
2167 siliconforks 332 return JS_TRUE;
2168 siliconforks 507 obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL);
2169 siliconforks 332 if (!obj)
2170     return JS_FALSE;
2171     }
2172     *rval = OBJECT_TO_JSVAL(obj);
2173     return JS_TRUE;
2174     }
2175    
2176 siliconforks 507 #ifdef JS_TRACER
2177    
2178     JSObject*
2179     js_NewObjectWithClassProto(JSContext *cx, JSClass *clasp, JSObject *proto,
2180     jsval privateSlotValue)
2181 siliconforks 460 {
2182 siliconforks 507 JS_ASSERT(!clasp->getObjectOps);
2183     JS_ASSERT(proto->map->ops == &js_ObjectOps);
2184 siliconforks 460
2185 siliconforks 507 JSObject* obj = js_NewGCObject(cx, GCX_OBJECT);
2186     if (!obj)
2187     return NULL;
2188 siliconforks 460
2189 siliconforks 507 obj->initSharingEmptyScope(clasp, proto, proto->getParent(), privateSlotValue);
2190     return obj;
2191     }
2192 siliconforks 460
2193 siliconforks 507 JSObject* FASTCALL
2194     js_Object_tn(JSContext* cx, JSObject* proto)
2195     {
2196     JS_ASSERT(!(js_ObjectClass.flags & JSCLASS_HAS_PRIVATE));
2197     return js_NewObjectWithClassProto(cx, &js_ObjectClass, proto, JSVAL_VOID);
2198 siliconforks 460 }
2199    
2200 siliconforks 507 JS_DEFINE_TRCINFO_1(js_Object,
2201     (2, (extern, CONSTRUCTOR_RETRY, js_Object_tn, CONTEXT, CALLEE_PROTOTYPE, 0, 0)))
2202 siliconforks 460
2203     static inline JSObject*
2204 siliconforks 507 NewNativeObject(JSContext* cx, JSClass* clasp, JSObject* proto,
2205     JSObject *parent, jsval privateSlotValue)
2206 siliconforks 460 {
2207     JS_ASSERT(JS_ON_TRACE(cx));
2208 siliconforks 507 JSObject* obj = js_NewGCObject(cx, GCX_OBJECT);
2209 siliconforks 460 if (!obj)
2210     return NULL;
2211    
2212 siliconforks 507 obj->init(clasp, proto, parent, privateSlotValue);
2213 siliconforks 460 return InitScopeForObject(cx, obj, proto, &js_ObjectOps) ? obj : NULL;
2214     }
2215    
2216     JSObject* FASTCALL
2217     js_NewInstance(JSContext *cx, JSClass *clasp, JSObject *ctor)
2218     {
2219     JS_ASSERT(HAS_FUNCTION_CLASS(ctor));
2220    
2221     JSAtom *atom = cx->runtime->atomState.classPrototypeAtom;
2222    
2223     JSScope *scope = OBJ_SCOPE(ctor);
2224     #ifdef JS_THREADSAFE
2225     if (scope->title.ownercx != cx)
2226     return NULL;
2227     #endif
2228 siliconforks 507 if (!scope->owned()) {
2229 siliconforks 460 scope = js_GetMutableScope(cx, ctor);
2230     if (!scope)
2231     return NULL;
2232     }
2233    
2234 siliconforks 507 JSScopeProperty *sprop = scope->lookup(ATOM_TO_JSID(atom));
2235 siliconforks 460 jsval pval = sprop ? STOBJ_GET_SLOT(ctor, sprop->slot) : JSVAL_HOLE;
2236    
2237     JSObject *proto;
2238     if (!JSVAL_IS_PRIMITIVE(pval)) {
2239     /* An object in ctor.prototype, let's use it as the new instance's proto. */
2240     proto = JSVAL_TO_OBJECT(pval);
2241     } else if (pval == JSVAL_HOLE) {
2242     /* No ctor.prototype yet, inline and optimize fun_resolve's prototype code. */
2243 siliconforks 507 proto = js_NewObject(cx, clasp, NULL, OBJ_GET_PARENT(cx, ctor));
2244 siliconforks 460 if (!proto)
2245     return NULL;
2246     if (!js_SetClassPrototype(cx, ctor, proto, JSPROP_ENUMERATE | JSPROP_PERMANENT))
2247     return NULL;
2248     } else {
2249     /* Primitive value in .prototype means we use Object.prototype for proto. */
2250     if (!js_GetClassPrototype(cx, JSVAL_TO_OBJECT(ctor->fslots[JSSLOT_PARENT]),
2251     INT_TO_JSID(JSProto_Object), &proto)) {
2252     return NULL;
2253     }
2254     }
2255    
2256 siliconforks 507 return NewNativeObject(cx, clasp, proto, ctor->getParent(),
2257     JSObject::defaultPrivate(clasp));
2258 siliconforks 460 }
2259    
2260     JS_DEFINE_CALLINFO_3(extern, CONSTRUCTOR_RETRY, js_NewInstance, CONTEXT, CLASS, OBJECT, 0, 0)
2261    
2262     #else /* !JS_TRACER */
2263    
2264     # define js_Object_trcinfo NULL
2265    
2266     #endif /* !JS_TRACER */
2267    
2268 siliconforks 332 /*
2269 siliconforks 460 * Given pc pointing after a property accessing bytecode, return true if the
2270     * access is "object-detecting" in the sense used by web scripts, e.g., when
2271     * checking whether document.all is defined.
2272     */
2273 siliconforks 507 JS_REQUIRES_STACK JSBool
2274 siliconforks 460 Detecting(JSContext *cx, jsbytecode *pc)
2275     {
2276     JSScript *script;
2277     jsbytecode *endpc;
2278     JSOp op;
2279     JSAtom *atom;
2280    
2281     script = cx->fp->script;
2282     endpc = script->code + script->length;
2283     for (;; pc += js_CodeSpec[op].length) {
2284 siliconforks 507 JS_ASSERT_IF(!cx->fp->imacpc, script->code <= pc && pc < endpc);
2285 siliconforks 460
2286     /* General case: a branch or equality op follows the access. */
2287     op = js_GetOpcode(cx, script, pc);
2288     if (js_CodeSpec[op].format & JOF_DETECTING)
2289     return JS_TRUE;
2290    
2291     switch (op) {
2292     case JSOP_NULL:
2293     /*
2294     * Special case #1: handle (document.all == null). Don't sweat
2295     * about JS1.2's revision of the equality operators here.
2296     */
2297     if (++pc < endpc) {
2298     op = js_GetOpcode(cx, script, pc);
2299     return *pc == JSOP_EQ || *pc == JSOP_NE;
2300     }
2301     return JS_FALSE;
2302    
2303     case JSOP_NAME:
2304     /*
2305     * Special case #2: handle (document.all == undefined). Don't
2306     * worry about someone redefining undefined, which was added by
2307     * Edition 3, so is read/write for backward compatibility.
2308     */
2309     GET_ATOM_FROM_BYTECODE(script, pc, 0, atom);
2310     if (atom == cx->runtime->atomState.typeAtoms[JSTYPE_VOID] &&
2311     (pc += js_CodeSpec[op].length) < endpc) {
2312     op = js_GetOpcode(cx, script, pc);
2313     return op == JSOP_EQ || op == JSOP_NE ||
2314     op == JSOP_STRICTEQ || op == JSOP_STRICTNE;
2315     }
2316     return JS_FALSE;
2317    
2318     default:
2319     /*
2320     * At this point, anything but an extended atom index prefix means
2321     * we're not detecting.
2322     */
2323     if (!(js_CodeSpec[op].format & JOF_INDEXBASE))
2324     return JS_FALSE;
2325     break;
2326     }
2327     }
2328     }
2329    
2330     /*
2331     * Infer lookup flags from the currently executing bytecode. This does
2332     * not attempt to infer JSRESOLVE_WITH, because the current bytecode
2333     * does not indicate whether we are in a with statement. Return defaultFlags
2334     * if a currently executing bytecode cannot be determined.
2335     */
2336 siliconforks 507 uintN
2337     js_InferFlags(JSContext *cx, uintN defaultFlags)
2338 siliconforks 460 {
2339 siliconforks 507 #ifdef JS_TRACER
2340     if (JS_ON_TRACE(cx))
2341     return cx->bailExit->lookupFlags;
2342     #endif
2343    
2344     JS_ASSERT_NOT_ON_TRACE(cx);
2345    
2346 siliconforks 460 JSStackFrame *fp;
2347     jsbytecode *pc;
2348     const JSCodeSpec *cs;
2349     uint32 format;
2350     uintN flags = 0;
2351    
2352     fp = js_GetTopStackFrame(cx);
2353     if (!fp || !fp->regs)
2354     return defaultFlags;
2355     pc = fp->regs->pc;
2356     cs = &js_CodeSpec[js_GetOpcode(cx, fp->script, pc)];
2357     format = cs->format;
2358     if (JOF_MODE(format) != JOF_NAME)
2359     flags |= JSRESOLVE_QUALIFIED;
2360     if ((format & (JOF_SET | JOF_FOR)) ||
2361     (fp->flags & JSFRAME_ASSIGNING)) {
2362     flags |= JSRESOLVE_ASSIGNING;
2363 siliconforks 507 } else if (cs->length >= 0) {
2364 siliconforks 460 pc += cs->length;
2365     if (pc < cx->fp->script->code + cx->fp->script->length && Detecting(cx, pc))
2366     flags |= JSRESOLVE_DETECTING;
2367     }
2368     if (format & JOF_DECLARING)
2369     flags |= JSRESOLVE_DECLARING;
2370     return flags;
2371     }
2372    
2373     /*
2374 siliconforks 332 * ObjectOps and Class for with-statement stack objects.
2375     */
2376     static JSBool
2377     with_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
2378     JSProperty **propp)
2379     {
2380 siliconforks 460 /* Fixes bug 463997 */
2381     uintN flags = cx->resolveFlags;
2382     if (flags == JSRESOLVE_INFER)
2383 siliconforks 507 flags = js_InferFlags(cx, flags);
2384 siliconforks 460 flags |= JSRESOLVE_WITH;
2385     JSAutoResolveFlags rf(cx, flags);
2386 siliconforks 332 JSObject *proto = OBJ_GET_PROTO(cx, obj);
2387     if (!proto)
2388     return js_LookupProperty(cx, obj, id, objp, propp);
2389 siliconforks 507 return proto->lookupProperty(cx, id, objp, propp);
2390 siliconforks 332 }
2391    
2392     static JSBool
2393     with_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
2394     {
2395     JSObject *proto = OBJ_GET_PROTO(cx, obj);
2396     if (!proto)
2397     return js_GetProperty(cx, obj, id, vp);
2398 siliconforks 507 return proto->getProperty(cx, id, vp);
2399 siliconforks 332 }
2400    
2401     static JSBool
2402     with_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
2403     {
2404     JSObject *proto = OBJ_GET_PROTO(cx, obj);
2405     if (!proto)
2406     return js_SetProperty(cx, obj, id, vp);
2407 siliconforks 507 return proto->setProperty(cx, id, vp);
2408 siliconforks 332 }
2409    
2410     static JSBool
2411     with_GetAttributes(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_GetAttributes(cx, obj, id, prop, attrsp);
2417 siliconforks 507 return proto->getAttributes(cx, id, prop, attrsp);
2418 siliconforks 332 }
2419    
2420     static JSBool
2421     with_SetAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop,
2422     uintN *attrsp)
2423     {
2424     JSObject *proto = OBJ_GET_PROTO(cx, obj);
2425     if (!proto)
2426     return js_SetAttributes(cx, obj, id, prop, attrsp);
2427 siliconforks 507 return proto->setAttributes(cx, id, prop, attrsp);
2428 siliconforks 332 }
2429    
2430     static JSBool
2431     with_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
2432     {
2433     JSObject *proto = OBJ_GET_PROTO(cx, obj);
2434     if (!proto)
2435     return js_DeleteProperty(cx, obj, id, rval);
2436 siliconforks 507 return proto->deleteProperty(cx, id, rval);
2437 siliconforks 332 }
2438    
2439     static JSBool
2440     with_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp)
2441     {
2442     JSObject *proto = OBJ_GET_PROTO(cx, obj);
2443     if (!proto)
2444     return js_DefaultValue(cx, obj, hint, vp);
2445 siliconforks 507 return proto->defaultValue(cx, hint, vp);
2446 siliconforks 332 }
2447    
2448     static JSBool
2449     with_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
2450     jsval *statep, jsid *idp)
2451     {
2452     JSObject *proto = OBJ_GET_PROTO(cx, obj);
2453     if (!proto)
2454     return js_Enumerate(cx, obj, enum_op, statep, idp);
2455 siliconforks 507 return proto->enumerate(cx, enum_op, statep, idp);
2456 siliconforks 332 }
2457    
2458     static JSBool
2459     with_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
2460     jsval *vp, uintN *attrsp)
2461     {
2462     JSObject *proto = OBJ_GET_PROTO(cx, obj);
2463     if (!proto)
2464     return js_CheckAccess(cx, obj, id, mode, vp, attrsp);
2465 siliconforks 507 return proto->checkAccess(cx, id, mode, vp, attrsp);
2466 siliconforks 332 }
2467    
2468     static JSObject *
2469     with_ThisObject(JSContext *cx, JSObject *obj)
2470     {
2471     JSObject *proto = OBJ_GET_PROTO(cx, obj);
2472     if (!proto)
2473     return obj;
2474 siliconforks 507 return proto->thisObject(cx);
2475 siliconforks 332 }
2476    
2477     JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps = {
2478 siliconforks 460 NULL,
2479 siliconforks 332 with_LookupProperty, js_DefineProperty,
2480     with_GetProperty, with_SetProperty,
2481     with_GetAttributes, with_SetAttributes,
2482     with_DeleteProperty, with_DefaultValue,
2483     with_Enumerate, with_CheckAccess,
2484     with_ThisObject, NATIVE_DROP_PROPERTY,
2485     NULL, NULL,
2486 siliconforks 460 NULL, js_TraceObject,
2487 siliconforks 507 js_Clear
2488 siliconforks 332 };
2489    
2490     static JSObjectOps *
2491     with_getObjectOps(JSContext *cx, JSClass *clasp)
2492     {
2493     return &js_WithObjectOps;
2494     }
2495    
2496     JSClass js_WithClass = {
2497     "With",
2498     JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_IS_ANONYMOUS,
2499     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
2500 siliconforks 507 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL,
2501 siliconforks 332 with_getObjectOps,
2502     0,0,0,0,0,0,0
2503     };
2504    
2505 siliconforks 460 JS_REQUIRES_STACK JSObject *
2506 siliconforks 332 js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
2507     {
2508     JSObject *obj;
2509    
2510 siliconforks 507 obj = js_NewObject(cx, &js_WithClass, proto, parent);
2511 siliconforks 332 if (!obj)
2512     return NULL;
2513 siliconforks 507 obj->setPrivate(cx->fp);
2514 siliconforks 332 OBJ_SET_BLOCK_DEPTH(cx, obj, depth);
2515     return