1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sw=4 et tw=78:
3  *
4  * ***** BEGIN LICENSE BLOCK *****
5  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is 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  * JavaScript API.
43  */
44 #include "jsstddef.h"
45 #include <ctype.h>
46 #include <stdarg.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include "jstypes.h"
50 #include "jsarena.h" /* Added by JSIFY */
51 #include "jsutil.h" /* Added by JSIFY */
52 #include "jsclist.h"
53 #include "jsdhash.h"
54 #include "jsprf.h"
55 #include "jsapi.h"
56 #include "jsarray.h"
57 #include "jsatom.h"
58 #include "jsbool.h"
59 #include "jscntxt.h"
60 #include "jsconfig.h"
61 #include "jsdate.h"
62 #include "jsdtoa.h"
63 #include "jsemit.h"
64 #include "jsexn.h"
65 #include "jsfun.h"
66 #include "jsgc.h"
67 #include "jsinterp.h"
68 #include "jslock.h"
69 #include "jsmath.h"
70 #include "jsnum.h"
71 #include "jsobj.h"
72 #include "jsopcode.h"
73 #include "jsparse.h"
74 #include "jsregexp.h"
75 #include "jsscan.h"
76 #include "jsscope.h"
77 #include "jsscript.h"
78 #include "jsstr.h"
79 #include "prmjtime.h"
80 
81 #if JS_HAS_FILE_OBJECT
82 #include "jsfile.h"
83 #endif
84 
85 #if JS_HAS_XML_SUPPORT
86 #include "jsxml.h"
87 #endif
88 
89 #if JS_HAS_GENERATORS
90 #include "jsiter.h"
91 #endif
92 
93 #ifdef HAVE_VA_LIST_AS_ARRAY
94 #define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
95 #else
96 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
97 #endif
98 
99 #if defined(JS_PARANOID_REQUEST) && defined(JS_THREADSAFE)
100 #define CHECK_REQUEST(cx)       JS_ASSERT(cx->requestDepth)
101 #else
102 #define CHECK_REQUEST(cx)       ((void)0)
103 #endif
104 
105 JS_PUBLIC_API(int64)
JS_Now()106 JS_Now()
107 {
108     return PRMJ_Now();
109 }
110 
111 JS_PUBLIC_API(jsval)
JS_GetNaNValue(JSContext * cx)112 JS_GetNaNValue(JSContext *cx)
113 {
114     return DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
115 }
116 
117 JS_PUBLIC_API(jsval)
JS_GetNegativeInfinityValue(JSContext * cx)118 JS_GetNegativeInfinityValue(JSContext *cx)
119 {
120     return DOUBLE_TO_JSVAL(cx->runtime->jsNegativeInfinity);
121 }
122 
123 JS_PUBLIC_API(jsval)
JS_GetPositiveInfinityValue(JSContext * cx)124 JS_GetPositiveInfinityValue(JSContext *cx)
125 {
126     return DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
127 }
128 
129 JS_PUBLIC_API(jsval)
JS_GetEmptyStringValue(JSContext * cx)130 JS_GetEmptyStringValue(JSContext *cx)
131 {
132     return STRING_TO_JSVAL(cx->runtime->emptyString);
133 }
134 
135 static JSBool
TryArgumentFormatter(JSContext * cx,const char ** formatp,JSBool fromJS,jsval ** vpp,va_list * app)136 TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS,
137                      jsval **vpp, va_list *app)
138 {
139     const char *format;
140     JSArgumentFormatMap *map;
141 
142     format = *formatp;
143     for (map = cx->argumentFormatMap; map; map = map->next) {
144         if (!strncmp(format, map->format, map->length)) {
145             *formatp = format + map->length;
146             return map->formatter(cx, format, fromJS, vpp, app);
147         }
148     }
149     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
150     return JS_FALSE;
151 }
152 
153 JS_PUBLIC_API(JSBool)
JS_ConvertArguments(JSContext * cx,uintN argc,jsval * argv,const char * format,...)154 JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format,
155                     ...)
156 {
157     va_list ap;
158     JSBool ok;
159 
160     va_start(ap, format);
161     ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap);
162     va_end(ap);
163     return ok;
164 }
165 
166 JS_PUBLIC_API(JSBool)
JS_ConvertArgumentsVA(JSContext * cx,uintN argc,jsval * argv,const char * format,va_list ap)167 JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv,
168                       const char *format, va_list ap)
169 {
170     jsval *sp;
171     JSBool required;
172     char c;
173     JSFunction *fun;
174     jsdouble d;
175     JSString *str;
176     JSObject *obj;
177 
178     CHECK_REQUEST(cx);
179     sp = argv;
180     required = JS_TRUE;
181     while ((c = *format++) != '\0') {
182         if (isspace(c))
183             continue;
184         if (c == '/') {
185             required = JS_FALSE;
186             continue;
187         }
188         if (sp == argv + argc) {
189             if (required) {
190                 fun = js_ValueToFunction(cx, &argv[-2], 0);
191                 if (fun) {
192                     char numBuf[12];
193                     JS_snprintf(numBuf, sizeof numBuf, "%u", argc);
194                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
195                                          JSMSG_MORE_ARGS_NEEDED,
196                                          JS_GetFunctionName(fun), numBuf,
197                                          (argc == 1) ? "" : "s");
198                 }
199                 return JS_FALSE;
200             }
201             break;
202         }
203         switch (c) {
204           case 'b':
205             if (!js_ValueToBoolean(cx, *sp, va_arg(ap, JSBool *)))
206                 return JS_FALSE;
207             break;
208           case 'c':
209             if (!js_ValueToUint16(cx, *sp, va_arg(ap, uint16 *)))
210                 return JS_FALSE;
211             break;
212           case 'i':
213             if (!js_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *)))
214                 return JS_FALSE;
215             break;
216           case 'u':
217             if (!js_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *)))
218                 return JS_FALSE;
219             break;
220           case 'j':
221             if (!js_ValueToInt32(cx, *sp, va_arg(ap, int32 *)))
222                 return JS_FALSE;
223             break;
224           case 'd':
225             if (!js_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *)))
226                 return JS_FALSE;
227             break;
228           case 'I':
229             if (!js_ValueToNumber(cx, *sp, &d))
230                 return JS_FALSE;
231             *va_arg(ap, jsdouble *) = js_DoubleToInteger(d);
232             break;
233           case 's':
234           case 'S':
235           case 'W':
236             str = js_ValueToString(cx, *sp);
237             if (!str)
238                 return JS_FALSE;
239             *sp = STRING_TO_JSVAL(str);
240             if (c == 's')
241                 *va_arg(ap, char **) = JS_GetStringBytes(str);
242             else if (c == 'W')
243                 *va_arg(ap, jschar **) = JS_GetStringChars(str);
244             else
245                 *va_arg(ap, JSString **) = str;
246             break;
247           case 'o':
248             if (!js_ValueToObject(cx, *sp, &obj))
249                 return JS_FALSE;
250             *sp = OBJECT_TO_JSVAL(obj);
251             *va_arg(ap, JSObject **) = obj;
252             break;
253           case 'f':
254             obj = js_ValueToFunctionObject(cx, sp, 0);
255             if (!obj)
256                 return JS_FALSE;
257             *va_arg(ap, JSFunction **) = (JSFunction *) JS_GetPrivate(cx, obj);
258             break;
259           case 'v':
260             *va_arg(ap, jsval *) = *sp;
261             break;
262           case '*':
263             break;
264           default:
265             format--;
266             if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp,
267                                       JS_ADDRESSOF_VA_LIST(ap))) {
268                 return JS_FALSE;
269             }
270             /* NB: the formatter already updated sp, so we continue here. */
271             continue;
272         }
273         sp++;
274     }
275     return JS_TRUE;
276 }
277 
278 JS_PUBLIC_API(jsval *)
JS_PushArguments(JSContext * cx,void ** markp,const char * format,...)279 JS_PushArguments(JSContext *cx, void **markp, const char *format, ...)
280 {
281     va_list ap;
282     jsval *argv;
283 
284     va_start(ap, format);
285     argv = JS_PushArgumentsVA(cx, markp, format, ap);
286     va_end(ap);
287     return argv;
288 }
289 
290 JS_PUBLIC_API(jsval *)
JS_PushArgumentsVA(JSContext * cx,void ** markp,const char * format,va_list ap)291 JS_PushArgumentsVA(JSContext *cx, void **markp, const char *format, va_list ap)
292 {
293     uintN argc;
294     jsval *argv, *sp;
295     char c;
296     const char *cp;
297     JSString *str;
298     JSFunction *fun;
299     JSStackHeader *sh;
300 
301     CHECK_REQUEST(cx);
302     *markp = NULL;
303     argc = 0;
304     for (cp = format; (c = *cp) != '\0'; cp++) {
305         /*
306          * Count non-space non-star characters as individual jsval arguments.
307          * This may over-allocate stack, but we'll fix below.
308          */
309         if (isspace(c) || c == '*')
310             continue;
311         argc++;
312     }
313     sp = js_AllocStack(cx, argc, markp);
314     if (!sp)
315         return NULL;
316     argv = sp;
317     while ((c = *format++) != '\0') {
318         if (isspace(c) || c == '*')
319             continue;
320         switch (c) {
321           case 'b':
322             *sp = BOOLEAN_TO_JSVAL((JSBool) va_arg(ap, int));
323             break;
324           case 'c':
325             *sp = INT_TO_JSVAL((uint16) va_arg(ap, unsigned int));
326             break;
327           case 'i':
328           case 'j':
329             if (!js_NewNumberValue(cx, (jsdouble) va_arg(ap, int32), sp))
330                 goto bad;
331             break;
332           case 'u':
333             if (!js_NewNumberValue(cx, (jsdouble) va_arg(ap, uint32), sp))
334                 goto bad;
335             break;
336           case 'd':
337           case 'I':
338             if (!js_NewDoubleValue(cx, va_arg(ap, jsdouble), sp))
339                 goto bad;
340             break;
341           case 's':
342             str = JS_NewStringCopyZ(cx, va_arg(ap, char *));
343             if (!str)
344                 goto bad;
345             *sp = STRING_TO_JSVAL(str);
346             break;
347           case 'W':
348             str = JS_NewUCStringCopyZ(cx, va_arg(ap, jschar *));
349             if (!str)
350                 goto bad;
351             *sp = STRING_TO_JSVAL(str);
352             break;
353           case 'S':
354             str = va_arg(ap, JSString *);
355             *sp = STRING_TO_JSVAL(str);
356             break;
357           case 'o':
358             *sp = OBJECT_TO_JSVAL(va_arg(ap, JSObject *));
359             break;
360           case 'f':
361             fun = va_arg(ap, JSFunction *);
362             *sp = fun ? OBJECT_TO_JSVAL(fun->object) : JSVAL_NULL;
363             break;
364           case 'v':
365             *sp = va_arg(ap, jsval);
366             break;
367           default:
368             format--;
369             if (!TryArgumentFormatter(cx, &format, JS_FALSE, &sp,
370                                       JS_ADDRESSOF_VA_LIST(ap))) {
371                 goto bad;
372             }
373             /* NB: the formatter already updated sp, so we continue here. */
374             continue;
375         }
376         sp++;
377     }
378 
379     /*
380      * We may have overallocated stack due to a multi-character format code
381      * handled by a JSArgumentFormatter.  Give back that stack space!
382      */
383     JS_ASSERT(sp <= argv + argc);
384     if (sp < argv + argc) {
385         /* Return slots not pushed to the current stack arena. */
386         cx->stackPool.current->avail = (jsuword)sp;
387 
388         /* Reduce the count of slots the GC will scan in this stack segment. */
389         sh = cx->stackHeaders;
390         JS_ASSERT(JS_STACK_SEGMENT(sh) + sh->nslots == argv + argc);
391         sh->nslots -= argc - (sp - argv);
392     }
393     return argv;
394 
395 bad:
396     js_FreeStack(cx, *markp);
397     return NULL;
398 }
399 
400 JS_PUBLIC_API(void)
JS_PopArguments(JSContext * cx,void * mark)401 JS_PopArguments(JSContext *cx, void *mark)
402 {
403     CHECK_REQUEST(cx);
404     js_FreeStack(cx, mark);
405 }
406 
407 JS_PUBLIC_API(JSBool)
JS_AddArgumentFormatter(JSContext * cx,const char * format,JSArgumentFormatter formatter)408 JS_AddArgumentFormatter(JSContext *cx, const char *format,
409                         JSArgumentFormatter formatter)
410 {
411     size_t length;
412     JSArgumentFormatMap **mpp, *map;
413 
414     length = strlen(format);
415     mpp = &cx->argumentFormatMap;
416     while ((map = *mpp) != NULL) {
417         /* Insert before any shorter string to match before prefixes. */
418         if (map->length < length)
419             break;
420         if (map->length == length && !strcmp(map->format, format))
421             goto out;
422         mpp = &map->next;
423     }
424     map = (JSArgumentFormatMap *) JS_malloc(cx, sizeof *map);
425     if (!map)
426         return JS_FALSE;
427     map->format = format;
428     map->length = length;
429     map->next = *mpp;
430     *mpp = map;
431 out:
432     map->formatter = formatter;
433     return JS_TRUE;
434 }
435 
436 JS_PUBLIC_API(void)
JS_RemoveArgumentFormatter(JSContext * cx,const char * format)437 JS_RemoveArgumentFormatter(JSContext *cx, const char *format)
438 {
439     size_t length;
440     JSArgumentFormatMap **mpp, *map;
441 
442     length = strlen(format);
443     mpp = &cx->argumentFormatMap;
444     while ((map = *mpp) != NULL) {
445         if (map->length == length && !strcmp(map->format, format)) {
446             *mpp = map->next;
447             JS_free(cx, map);
448             return;
449         }
450         mpp = &map->next;
451     }
452 }
453 
454 JS_PUBLIC_API(JSBool)
JS_ConvertValue(JSContext * cx,jsval v,JSType type,jsval * vp)455 JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
456 {
457     JSBool ok, b;
458     JSObject *obj;
459     JSString *str;
460     jsdouble d, *dp;
461 
462     CHECK_REQUEST(cx);
463     switch (type) {
464       case JSTYPE_VOID:
465         *vp = JSVAL_VOID;
466         ok = JS_TRUE;
467         break;
468       case JSTYPE_OBJECT:
469         ok = js_ValueToObject(cx, v, &obj);
470         if (ok)
471             *vp = OBJECT_TO_JSVAL(obj);
472         break;
473       case JSTYPE_FUNCTION:
474         *vp = v;
475         obj = js_ValueToFunctionObject(cx, vp, JSV2F_SEARCH_STACK);
476         ok = (obj != NULL);
477         break;
478       case JSTYPE_STRING:
479         str = js_ValueToString(cx, v);
480         ok = (str != NULL);
481         if (ok)
482             *vp = STRING_TO_JSVAL(str);
483         break;
484       case JSTYPE_NUMBER:
485         ok = js_ValueToNumber(cx, v, &d);
486         if (ok) {
487             dp = js_NewDouble(cx, d, 0);
488             ok = (dp != NULL);
489             if (ok)
490                 *vp = DOUBLE_TO_JSVAL(dp);
491         }
492         break;
493       case JSTYPE_BOOLEAN:
494         ok = js_ValueToBoolean(cx, v, &b);
495         if (ok)
496             *vp = BOOLEAN_TO_JSVAL(b);
497         break;
498       default: {
499         char numBuf[12];
500         JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
501         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE,
502                              numBuf);
503         ok = JS_FALSE;
504         break;
505       }
506     }
507     return ok;
508 }
509 
510 JS_PUBLIC_API(JSBool)
JS_ValueToObject(JSContext * cx,jsval v,JSObject ** objp)511 JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp)
512 {
513     CHECK_REQUEST(cx);
514     return js_ValueToObject(cx, v, objp);
515 }
516 
517 JS_PUBLIC_API(JSFunction *)
JS_ValueToFunction(JSContext * cx,jsval v)518 JS_ValueToFunction(JSContext *cx, jsval v)
519 {
520     CHECK_REQUEST(cx);
521     return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
522 }
523 
524 JS_PUBLIC_API(JSFunction *)
JS_ValueToConstructor(JSContext * cx,jsval v)525 JS_ValueToConstructor(JSContext *cx, jsval v)
526 {
527     CHECK_REQUEST(cx);
528     return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
529 }
530 
531 JS_PUBLIC_API(JSString *)
JS_ValueToString(JSContext * cx,jsval v)532 JS_ValueToString(JSContext *cx, jsval v)
533 {
534     CHECK_REQUEST(cx);
535     return js_ValueToString(cx, v);
536 }
537 
538 JS_PUBLIC_API(JSBool)
JS_ValueToNumber(JSContext * cx,jsval v,jsdouble * dp)539 JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
540 {
541     CHECK_REQUEST(cx);
542     return js_ValueToNumber(cx, v, dp);
543 }
544 
545 JS_PUBLIC_API(JSBool)
JS_ValueToECMAInt32(JSContext * cx,jsval v,int32 * ip)546 JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
547 {
548     CHECK_REQUEST(cx);
549     return js_ValueToECMAInt32(cx, v, ip);
550 }
551 
552 JS_PUBLIC_API(JSBool)
JS_ValueToECMAUint32(JSContext * cx,jsval v,uint32 * ip)553 JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
554 {
555     CHECK_REQUEST(cx);
556     return js_ValueToECMAUint32(cx, v, ip);
557 }
558 
559 JS_PUBLIC_API(JSBool)
JS_ValueToInt32(JSContext * cx,jsval v,int32 * ip)560 JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
561 {
562     CHECK_REQUEST(cx);
563     return js_ValueToInt32(cx, v, ip);
564 }
565 
566 JS_PUBLIC_API(JSBool)
JS_ValueToUint16(JSContext * cx,jsval v,uint16 * ip)567 JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
568 {
569     CHECK_REQUEST(cx);
570     return js_ValueToUint16(cx, v, ip);
571 }
572 
573 JS_PUBLIC_API(JSBool)
JS_ValueToBoolean(JSContext * cx,jsval v,JSBool * bp)574 JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
575 {
576     CHECK_REQUEST(cx);
577     return js_ValueToBoolean(cx, v, bp);
578 }
579 
580 JS_PUBLIC_API(JSType)
JS_TypeOfValue(JSContext * cx,jsval v)581 JS_TypeOfValue(JSContext *cx, jsval v)
582 {
583     JSType type;
584     JSObject *obj;
585     JSObjectOps *ops;
586     JSClass *clasp;
587 
588     CHECK_REQUEST(cx);
589     if (JSVAL_IS_OBJECT(v)) {
590         type = JSTYPE_OBJECT;           /* XXXbe JSTYPE_NULL for JS2 */
591         obj = JSVAL_TO_OBJECT(v);
592         if (obj) {
593             ops = obj->map->ops;
594 #if JS_HAS_XML_SUPPORT
595             if (ops == &js_XMLObjectOps.base) {
596                 type = JSTYPE_XML;
597             } else
598 #endif
599             {
600                 /*
601                  * ECMA 262, 11.4.3 says that any native object that implements
602                  * [[Call]] should be of type "function". Note that RegExp and
603                  * Script are both of type "function" for compatibility with
604                  * older SpiderMonkeys.
605                  */
606                 clasp = OBJ_GET_CLASS(cx, obj);
607                 if ((ops == &js_ObjectOps)
608                     ? (clasp->call
609                        ? (clasp == &js_RegExpClass || clasp == &js_ScriptClass)
610                        : clasp == &js_FunctionClass)
611                     : ops->call != NULL) {
612                     type = JSTYPE_FUNCTION;
613                 } else {
614 #ifdef NARCISSUS
615                     if (!OBJ_GET_PROPERTY(cx, obj,
616                                           ATOM_TO_JSID(cx->runtime->atomState
617                                                        .callAtom),
618                                           &v)) {
619                         JS_ClearPendingException(cx);
620                     } else if (VALUE_IS_FUNCTION(cx, v)) {
621                         type = JSTYPE_FUNCTION;
622                     }
623 #endif
624                 }
625             }
626         }
627     } else if (JSVAL_IS_NUMBER(v)) {
628         type = JSTYPE_NUMBER;
629     } else if (JSVAL_IS_STRING(v)) {
630         type = JSTYPE_STRING;
631     } else if (JSVAL_IS_BOOLEAN(v)) {
632         type = JSTYPE_BOOLEAN;
633     } else {
634         type = JSTYPE_VOID;
635     }
636     return type;
637 }
638 
639 JS_PUBLIC_API(const char *)
JS_GetTypeName(JSContext * cx,JSType type)640 JS_GetTypeName(JSContext *cx, JSType type)
641 {
642     if ((uintN)type >= (uintN)JSTYPE_LIMIT)
643         return NULL;
644     return js_type_strs[type];
645 }
646 
647 /************************************************************************/
648 
649 JS_PUBLIC_API(JSRuntime *)
JS_NewRuntime(uint32 maxbytes)650 JS_NewRuntime(uint32 maxbytes)
651 {
652     JSRuntime *rt;
653 
654 #ifdef DEBUG
655     static JSBool didFirstChecks;
656 
657     if (!didFirstChecks) {
658         /*
659          * This code asserts that the numbers associated with the error names
660          * in jsmsg.def are monotonically increasing.  It uses values for the
661          * error names enumerated in jscntxt.c.  It's not a compile-time check
662          * but it's better than nothing.
663          */
664         int errorNumber = 0;
665 #define MSG_DEF(name, number, count, exception, format)                       \
666     JS_ASSERT(name == errorNumber++);
667 #include "js.msg"
668 #undef MSG_DEF
669 
670 #define MSG_DEF(name, number, count, exception, format)                       \
671     JS_BEGIN_MACRO                                                            \
672         uintN numfmtspecs = 0;                                                \
673         const char *fmt;                                                      \
674         for (fmt = format; *fmt != '\0'; fmt++) {                             \
675             if (*fmt == '{' && isdigit(fmt[1]))                               \
676                 ++numfmtspecs;                                                \
677         }                                                                     \
678         JS_ASSERT(count == numfmtspecs);                                      \
679     JS_END_MACRO;
680 #include "js.msg"
681 #undef MSG_DEF
682 
683         didFirstChecks = JS_TRUE;
684     }
685 #endif /* DEBUG */
686 
687     rt = (JSRuntime *) malloc(sizeof(JSRuntime));
688     if (!rt)
689         return NULL;
690 
691     /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
692     memset(rt, 0, sizeof(JSRuntime));
693     JS_INIT_CLIST(&rt->contextList);
694     JS_INIT_CLIST(&rt->trapList);
695     JS_INIT_CLIST(&rt->watchPointList);
696 
697     if (!js_InitGC(rt, maxbytes))
698         goto bad;
699 #ifdef JS_THREADSAFE
700     if (PR_FAILURE == PR_NewThreadPrivateIndex(&rt->threadTPIndex,
701                                                js_ThreadDestructorCB)) {
702         goto bad;
703     }
704     rt->gcLock = JS_NEW_LOCK();
705     if (!rt->gcLock)
706         goto bad;
707     rt->gcDone = JS_NEW_CONDVAR(rt->gcLock);
708     if (!rt->gcDone)
709         goto bad;
710     rt->requestDone = JS_NEW_CONDVAR(rt->gcLock);
711     if (!rt->requestDone)
712         goto bad;
713     /* this is asymmetric with JS_ShutDown: */
714     if (!js_SetupLocks(8, 16))
715         goto bad;
716     rt->rtLock = JS_NEW_LOCK();
717     if (!rt->rtLock)
718         goto bad;
719     rt->stateChange = JS_NEW_CONDVAR(rt->gcLock);
720     if (!rt->stateChange)
721         goto bad;
722     rt->setSlotLock = JS_NEW_LOCK();
723     if (!rt->setSlotLock)
724         goto bad;
725     rt->setSlotDone = JS_NEW_CONDVAR(rt->setSlotLock);
726     if (!rt->setSlotDone)
727         goto bad;
728     rt->scopeSharingDone = JS_NEW_CONDVAR(rt->gcLock);
729     if (!rt->scopeSharingDone)
730         goto bad;
731     rt->scopeSharingTodo = NO_SCOPE_SHARING_TODO;
732 #endif
733     rt->propertyCache.empty = JS_TRUE;
734     if (!js_InitPropertyTree(rt))
735         goto bad;
736     return rt;
737 
738 bad:
739     JS_DestroyRuntime(rt);
740     return NULL;
741 }
742 
743 JS_PUBLIC_API(void)
JS_DestroyRuntime(JSRuntime * rt)744 JS_DestroyRuntime(JSRuntime *rt)
745 {
746 #ifdef DEBUG
747     /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */
748     if (!JS_CLIST_IS_EMPTY(&rt->contextList)) {
749         JSContext *cx, *iter = NULL;
750         uintN cxcount = 0;
751         while ((cx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL)
752             cxcount++;
753         fprintf(stderr,
754 "JS API usage error: %u contexts left in runtime upon JS_DestroyRuntime.\n",
755                 cxcount);
756     }
757 #endif
758 
759     js_FreeRuntimeScriptState(rt);
760     js_FinishAtomState(&rt->atomState);
761     js_FinishGC(rt);
762 #ifdef JS_THREADSAFE
763     if (rt->gcLock)
764         JS_DESTROY_LOCK(rt->gcLock);
765     if (rt->gcDone)
766         JS_DESTROY_CONDVAR(rt->gcDone);
767     if (rt->requestDone)
768         JS_DESTROY_CONDVAR(rt->requestDone);
769     if (rt->rtLock)
770         JS_DESTROY_LOCK(rt->rtLock);
771     if (rt->stateChange)
772         JS_DESTROY_CONDVAR(rt->stateChange);
773     if (rt->setSlotLock)
774         JS_DESTROY_LOCK(rt->setSlotLock);
775     if (rt->setSlotDone)
776         JS_DESTROY_CONDVAR(rt->setSlotDone);
777     if (rt->scopeSharingDone)
778         JS_DESTROY_CONDVAR(rt->scopeSharingDone);
779 #else
780     GSN_CACHE_CLEAR(&rt->gsnCache);
781 #endif
782     js_FinishPropertyTree(rt);
783     free(rt);
784 }
785 
786 JS_PUBLIC_API(void)
JS_ShutDown(void)787 JS_ShutDown(void)
788 {
789     js_FinishDtoa();
790 #ifdef JS_THREADSAFE
791     js_CleanupLocks();
792 #endif
793 }
794 
795 JS_PUBLIC_API(void *)
JS_GetRuntimePrivate(JSRuntime * rt)796 JS_GetRuntimePrivate(JSRuntime *rt)
797 {
798     return rt->data;
799 }
800 
801 JS_PUBLIC_API(void)
JS_SetRuntimePrivate(JSRuntime * rt,void * data)802 JS_SetRuntimePrivate(JSRuntime *rt, void *data)
803 {
804     rt->data = data;
805 }
806 
807 #ifdef JS_THREADSAFE
808 
809 JS_PUBLIC_API(void)
JS_BeginRequest(JSContext * cx)810 JS_BeginRequest(JSContext *cx)
811 {
812     JSRuntime *rt;
813 
814     JS_ASSERT(cx->thread->id == js_CurrentThreadId());
815     if (!cx->requestDepth) {
816         /* Wait until the GC is finished. */
817         rt = cx->runtime;
818         JS_LOCK_GC(rt);
819 
820         /* NB: we use cx->thread here, not js_GetCurrentThread(). */
821         if (rt->gcThread != cx->thread) {
822             while (rt->gcLevel > 0)
823                 JS_AWAIT_GC_DONE(rt);
824         }
825 
826         /* Indicate that a request is running. */
827         rt->requestCount++;
828         cx->requestDepth = 1;
829         JS_UNLOCK_GC(rt);
830         return;
831     }
832     cx->requestDepth++;
833 }
834 
835 JS_PUBLIC_API(void)
JS_EndRequest(JSContext * cx)836 JS_EndRequest(JSContext *cx)
837 {
838     JSRuntime *rt;
839     JSScope *scope, **todop;
840     uintN nshares;
841 
842     CHECK_REQUEST(cx);
843     JS_ASSERT(cx->requestDepth > 0);
844     if (cx->requestDepth == 1) {
845         /* Lock before clearing to interlock with ClaimScope, in jslock.c. */
846         rt = cx->runtime;
847         JS_LOCK_GC(rt);
848         cx->requestDepth = 0;
849 
850         /* See whether cx has any single-threaded scopes to start sharing. */
851         todop = &rt->scopeSharingTodo;
852         nshares = 0;
853         while ((scope = *todop) != NO_SCOPE_SHARING_TODO) {
854             if (scope->ownercx != cx) {
855                 todop = &scope->u.link;
856                 continue;
857             }
858             *todop = scope->u.link;
859             scope->u.link = NULL;       /* null u.link for sanity ASAP */
860 
861             /*
862              * If js_DropObjectMap returns null, we held the last ref to scope.
863              * The waiting thread(s) must have been killed, after which the GC
864              * collected the object that held this scope.  Unlikely, because it
865              * requires that the GC ran (e.g., from a branch callback) during
866              * this request, but possible.
867              */
868             if (js_DropObjectMap(cx, &scope->map, NULL)) {
869                 js_InitLock(&scope->lock);
870                 scope->u.count = 0;                 /* NULL may not pun as 0 */
871                 js_FinishSharingScope(rt, scope);   /* set ownercx = NULL */
872                 nshares++;
873             }
874         }
875         if (nshares)
876             JS_NOTIFY_ALL_CONDVAR(rt->scopeSharingDone);
877 
878         /* Give the GC a chance to run if this was the last request running. */
879         JS_ASSERT(rt->requestCount > 0);
880         rt->requestCount--;
881         if (rt->requestCount == 0)
882             JS_NOTIFY_REQUEST_DONE(rt);
883 
884         JS_UNLOCK_GC(rt);
885         return;
886     }
887 
888     cx->requestDepth--;
889 }
890 
891 /* Yield to pending GC operations, regardless of request depth */
892 JS_PUBLIC_API(void)
JS_YieldRequest(JSContext * cx)893 JS_YieldRequest(JSContext *cx)
894 {
895     JSRuntime *rt;
896 
897     JS_ASSERT(cx->thread);
898     CHECK_REQUEST(cx);
899 
900     rt = cx->runtime;
901     JS_LOCK_GC(rt);
902     JS_ASSERT(rt->requestCount > 0);
903     rt->requestCount--;
904     if (rt->requestCount == 0)
905         JS_NOTIFY_REQUEST_DONE(rt);
906     JS_UNLOCK_GC(rt);
907     /* XXXbe give the GC or another request calling it a chance to run here?
908              Assumes FIFO scheduling */
909     JS_LOCK_GC(rt);
910     if (rt->gcThread != cx->thread) {
911         while (rt->gcLevel > 0)
912             JS_AWAIT_GC_DONE(rt);
913     }
914     rt->requestCount++;
915     JS_UNLOCK_GC(rt);
916 }
917 
918 JS_PUBLIC_API(jsrefcount)
JS_SuspendRequest(JSContext * cx)919 JS_SuspendRequest(JSContext *cx)
920 {
921     jsrefcount saveDepth = cx->requestDepth;
922 
923     while (cx->requestDepth)
924         JS_EndRequest(cx);
925     return saveDepth;
926 }
927 
928 JS_PUBLIC_API(void)
JS_ResumeRequest(JSContext * cx,jsrefcount saveDepth)929 JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth)
930 {
931     JS_ASSERT(!cx->requestDepth);
932     while (--saveDepth >= 0)
933         JS_BeginRequest(cx);
934 }
935 
936 #endif /* JS_THREADSAFE */
937 
938 JS_PUBLIC_API(void)
JS_Lock(JSRuntime * rt)939 JS_Lock(JSRuntime *rt)
940 {
941     JS_LOCK_RUNTIME(rt);
942 }
943 
944 JS_PUBLIC_API(void)
JS_Unlock(JSRuntime * rt)945 JS_Unlock(JSRuntime *rt)
946 {
947     JS_UNLOCK_RUNTIME(rt);
948 }
949 
950 JS_PUBLIC_API(JSContextCallback)
JS_SetContextCallback(JSRuntime * rt,JSContextCallback cxCallback)951 JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback)
952 {
953     JSContextCallback old;
954 
955     old = rt->cxCallback;
956     rt->cxCallback = cxCallback;
957     return old;
958 }
959 
960 JS_PUBLIC_API(JSContext *)
JS_NewContext(JSRuntime * rt,size_t stackChunkSize)961 JS_NewContext(JSRuntime *rt, size_t stackChunkSize)
962 {
963     return js_NewContext(rt, stackChunkSize);
964 }
965 
966 JS_PUBLIC_API(void)
JS_DestroyContext(JSContext * cx)967 JS_DestroyContext(JSContext *cx)
968 {
969     js_DestroyContext(cx, JSDCM_FORCE_GC);
970 }
971 
972 JS_PUBLIC_API(void)
JS_DestroyContextNoGC(JSContext * cx)973 JS_DestroyContextNoGC(JSContext *cx)
974 {
975     js_DestroyContext(cx, JSDCM_NO_GC);
976 }
977 
978 JS_PUBLIC_API(void)
JS_DestroyContextMaybeGC(JSContext * cx)979 JS_DestroyContextMaybeGC(JSContext *cx)
980 {
981     js_DestroyContext(cx, JSDCM_MAYBE_GC);
982 }
983 
984 JS_PUBLIC_API(void *)
JS_GetContextPrivate(JSContext * cx)985 JS_GetContextPrivate(JSContext *cx)
986 {
987     return cx->data;
988 }
989 
990 JS_PUBLIC_API(void)
JS_SetContextPrivate(JSContext * cx,void * data)991 JS_SetContextPrivate(JSContext *cx, void *data)
992 {
993     cx->data = data;
994 }
995 
996 JS_PUBLIC_API(JSRuntime *)
JS_GetRuntime(JSContext * cx)997 JS_GetRuntime(JSContext *cx)
998 {
999     return cx->runtime;
1000 }
1001 
1002 JS_PUBLIC_API(JSContext *)
JS_ContextIterator(JSRuntime * rt,JSContext ** iterp)1003 JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
1004 {
1005     return js_ContextIterator(rt, JS_TRUE, iterp);
1006 }
1007 
1008 JS_PUBLIC_API(JSVersion)
JS_GetVersion(JSContext * cx)1009 JS_GetVersion(JSContext *cx)
1010 {
1011     return cx->version & JSVERSION_MASK;
1012 }
1013 
1014 JS_PUBLIC_API(JSVersion)
JS_SetVersion(JSContext * cx,JSVersion version)1015 JS_SetVersion(JSContext *cx, JSVersion version)
1016 {
1017     JSVersion oldVersion;
1018 
1019     JS_ASSERT(version != JSVERSION_UNKNOWN);
1020     JS_ASSERT((version & ~JSVERSION_MASK) == 0);
1021 
1022     oldVersion = cx->version & JSVERSION_MASK;
1023     if (version == oldVersion)
1024         return oldVersion;
1025 
1026     /* We no longer support 1.4 or below. */
1027     if (version != JSVERSION_DEFAULT && version <= JSVERSION_1_4)
1028         return oldVersion;
1029 
1030     cx->version = (cx->version & ~JSVERSION_MASK) | version;
1031     js_OnVersionChange(cx);
1032     return oldVersion;
1033 }
1034 
1035 static struct v2smap {
1036     JSVersion   version;
1037     const char  *string;
1038 } v2smap[] = {
1039     {JSVERSION_1_0,     "1.0"},
1040     {JSVERSION_1_1,     "1.1"},
1041     {JSVERSION_1_2,     "1.2"},
1042     {JSVERSION_1_3,     "1.3"},
1043     {JSVERSION_1_4,     "1.4"},
1044     {JSVERSION_ECMA_3,  "ECMAv3"},
1045     {JSVERSION_1_5,     "1.5"},
1046     {JSVERSION_1_6,     "1.6"},
1047     {JSVERSION_1_7,     "1.7"},
1048     {JSVERSION_DEFAULT, js_default_str},
1049     {JSVERSION_UNKNOWN, NULL},          /* must be last, NULL is sentinel */
1050 };
1051 
1052 JS_PUBLIC_API(const char *)
JS_VersionToString(JSVersion version)1053 JS_VersionToString(JSVersion version)
1054 {
1055     int i;
1056 
1057     for (i = 0; v2smap[i].string; i++)
1058         if (v2smap[i].version == version)
1059             return v2smap[i].string;
1060     return "unknown";
1061 }
1062 
1063 JS_PUBLIC_API(JSVersion)
JS_StringToVersion(const char * string)1064 JS_StringToVersion(const char *string)
1065 {
1066     int i;
1067 
1068     for (i = 0; v2smap[i].string; i++)
1069         if (strcmp(v2smap[i].string, string) == 0)
1070             return v2smap[i].version;
1071     return JSVERSION_UNKNOWN;
1072 }
1073 
1074 JS_PUBLIC_API(uint32)
JS_GetOptions(JSContext * cx)1075 JS_GetOptions(JSContext *cx)
1076 {
1077     return cx->options;
1078 }
1079 
1080 #define SYNC_OPTIONS_TO_VERSION(cx)                                           \
1081     JS_BEGIN_MACRO                                                            \
1082         if ((cx)->options & JSOPTION_XML)                                     \
1083             (cx)->version |= JSVERSION_HAS_XML;                               \
1084         else                                                                  \
1085             (cx)->version &= ~JSVERSION_HAS_XML;                              \
1086     JS_END_MACRO
1087 
1088 JS_PUBLIC_API(uint32)
JS_SetOptions(JSContext * cx,uint32 options)1089 JS_SetOptions(JSContext *cx, uint32 options)
1090 {
1091     uint32 oldopts = cx->options;
1092     cx->options = options;
1093     SYNC_OPTIONS_TO_VERSION(cx);
1094     return oldopts;
1095 }
1096 
1097 JS_PUBLIC_API(uint32)
JS_ToggleOptions(JSContext * cx,uint32 options)1098 JS_ToggleOptions(JSContext *cx, uint32 options)
1099 {
1100     uint32 oldopts = cx->options;
1101     cx->options ^= options;
1102     SYNC_OPTIONS_TO_VERSION(cx);
1103     return oldopts;
1104 }
1105 
1106 JS_PUBLIC_API(const char *)
JS_GetImplementationVersion(void)1107 JS_GetImplementationVersion(void)
1108 {
1109     return "JavaScript-C 1.7.0 2007-10-03";
1110 }
1111 
1112 
1113 JS_PUBLIC_API(JSObject *)
JS_GetGlobalObject(JSContext * cx)1114 JS_GetGlobalObject(JSContext *cx)
1115 {
1116     return cx->globalObject;
1117 }
1118 
1119 JS_PUBLIC_API(void)
JS_SetGlobalObject(JSContext * cx,JSObject * obj)1120 JS_SetGlobalObject(JSContext *cx, JSObject *obj)
1121 {
1122     cx->globalObject = obj;
1123 
1124 #if JS_HAS_XML_SUPPORT
1125     cx->xmlSettingFlags = 0;
1126 #endif
1127 }
1128 
1129 JSObject *
js_InitFunctionAndObjectClasses(JSContext * cx,JSObject * obj)1130 js_InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
1131 {
1132     JSDHashTable *table;
1133     JSBool resolving;
1134     JSRuntime *rt;
1135     JSResolvingKey key;
1136     JSResolvingEntry *entry;
1137     JSObject *fun_proto, *obj_proto;
1138 
1139     /* If cx has no global object, use obj so prototypes can be found. */
1140     if (!cx->globalObject)
1141         JS_SetGlobalObject(cx, obj);
1142 
1143     /* Record Function and Object in cx->resolvingTable, if we are resolving. */
1144     table = cx->resolvingTable;
1145     resolving = (table && table->entryCount);
1146     rt = cx->runtime;
1147     key.obj = obj;
1148     if (resolving) {
1149         key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]);
1150         entry = (JSResolvingEntry *)
1151                 JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
1152         if (entry && entry->key.obj && (entry->flags & JSRESFLAG_LOOKUP)) {
1153             /* Already resolving Function, record Object too. */
1154             JS_ASSERT(entry->key.obj == obj);
1155             key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
1156             entry = (JSResolvingEntry *)
1157                     JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
1158         }
1159         if (!entry) {
1160             JS_ReportOutOfMemory(cx);
1161             return NULL;
1162         }
1163         JS_ASSERT(!entry->key.obj && entry->flags == 0);
1164         entry->key = key;
1165         entry->flags = JSRESFLAG_LOOKUP;
1166     } else {
1167         key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
1168         if (!js_StartResolving(cx, &key, JSRESFLAG_LOOKUP, &entry))
1169             return NULL;
1170 
1171         key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]);
1172         if (!js_StartResolving(cx, &key, JSRESFLAG_LOOKUP, &entry)) {
1173             key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
1174             JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
1175             return NULL;
1176         }
1177 
1178         table = cx->resolvingTable;
1179     }
1180 
1181     /* Initialize the function class first so constructors can be made. */
1182     fun_proto = js_InitFunctionClass(cx, obj);
1183     if (!fun_proto)
1184         goto out;
1185 
1186     /* Initialize the object class next so Object.prototype works. */
1187     obj_proto = js_InitObjectClass(cx, obj);
1188     if (!obj_proto) {
1189         fun_proto = NULL;
1190         goto out;
1191     }
1192 
1193     /* Function.prototype and the global object delegate to Object.prototype. */
1194     OBJ_SET_PROTO(cx, fun_proto, obj_proto);
1195     if (!OBJ_GET_PROTO(cx, obj))
1196         OBJ_SET_PROTO(cx, obj, obj_proto);
1197 
1198 out:
1199     /* If resolving, remove the other entry (Object or Function) from table. */
1200     JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
1201     if (!resolving) {
1202         /* If not resolving, remove the first entry added above, for Object. */
1203         JS_ASSERT(key.id ==                                                   \
1204                   ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]));
1205         key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
1206         JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
1207     }
1208     return fun_proto;
1209 }
1210 
1211 JS_PUBLIC_API(JSBool)
JS_InitStandardClasses(JSContext * cx,JSObject * obj)1212 JS_InitStandardClasses(JSContext *cx, JSObject *obj)
1213 {
1214     JSAtom *atom;
1215 
1216     CHECK_REQUEST(cx);
1217 
1218     /* Define a top-level property 'undefined' with the undefined value. */
1219     atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
1220     if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1221                              NULL, NULL, JSPROP_PERMANENT, NULL)) {
1222         return JS_FALSE;
1223     }
1224 
1225     /* Function and Object require cooperative bootstrapping magic. */
1226     if (!js_InitFunctionAndObjectClasses(cx, obj))
1227         return JS_FALSE;
1228 
1229     /* Initialize the rest of the standard objects and functions. */
1230     return js_InitArrayClass(cx, obj) &&
1231            js_InitBlockClass(cx, obj) &&
1232            js_InitBooleanClass(cx, obj) &&
1233            js_InitCallClass(cx, obj) &&
1234            js_InitExceptionClasses(cx, obj) &&
1235            js_InitMathClass(cx, obj) &&
1236            js_InitNumberClass(cx, obj) &&
1237            js_InitRegExpClass(cx, obj) &&
1238            js_InitStringClass(cx, obj) &&
1239 #if JS_HAS_SCRIPT_OBJECT
1240            js_InitScriptClass(cx, obj) &&
1241 #endif
1242 #if JS_HAS_XML_SUPPORT
1243            js_InitXMLClasses(cx, obj) &&
1244 #endif
1245 #if JS_HAS_FILE_OBJECT
1246            js_InitFileClass(cx, obj) &&
1247 #endif
1248 #if JS_HAS_GENERATORS
1249            js_InitIteratorClasses(cx, obj) &&
1250 #endif
1251            js_InitDateClass(cx, obj);
1252 }
1253 
1254 #define ATOM_OFFSET(name)       offsetof(JSAtomState,name##Atom)
1255 #define CLASS_ATOM_OFFSET(name) offsetof(JSAtomState,classAtoms[JSProto_##name])
1256 #define OFFSET_TO_ATOM(rt,off)  (*(JSAtom **)((char*)&(rt)->atomState + (off)))
1257 #define CLASP(name)             (JSClass *)&js_##name##Class
1258 
1259 #define EAGER_ATOM(name)            ATOM_OFFSET(name), NULL
1260 #define EAGER_CLASS_ATOM(name)      CLASS_ATOM_OFFSET(name), NULL
1261 #define EAGER_ATOM_AND_CLASP(name)  EAGER_CLASS_ATOM(name), CLASP(name)
1262 #define LAZY_ATOM(name)             ATOM_OFFSET(lazy.name), js_##name##_str
1263 
1264 typedef struct JSStdName {
1265     JSObjectOp  init;
1266     size_t      atomOffset;     /* offset of atom pointer in JSAtomState */
1267     const char  *name;          /* null if atom is pre-pinned, else name */
1268     JSClass     *clasp;
1269 } JSStdName;
1270 
1271 static JSAtom *
StdNameToAtom(JSContext * cx,JSStdName * stdn)1272 StdNameToAtom(JSContext *cx, JSStdName *stdn)
1273 {
1274     size_t offset;
1275     JSAtom *atom;
1276     const char *name;
1277 
1278     offset = stdn->atomOffset;
1279     atom = OFFSET_TO_ATOM(cx->runtime, offset);
1280     if (!atom) {
1281         name = stdn->name;
1282         if (name) {
1283             atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED);
1284             OFFSET_TO_ATOM(cx->runtime, offset) = atom;
1285         }
1286     }
1287     return atom;
1288 }
1289 
1290 /*
1291  * Table of class initializers and their atom offsets in rt->atomState.
1292  * If you add a "standard" class, remember to update this table.
1293  */
1294 static JSStdName standard_class_atoms[] = {
1295     {js_InitFunctionAndObjectClasses,   EAGER_ATOM_AND_CLASP(Function)},
1296     {js_InitFunctionAndObjectClasses,   EAGER_ATOM_AND_CLASP(Object)},
1297     {js_InitArrayClass,                 EAGER_ATOM_AND_CLASP(Array)},
1298     {js_InitBlockClass,                 EAGER_ATOM_AND_CLASP(Block)},
1299     {js_InitBooleanClass,               EAGER_ATOM_AND_CLASP(Boolean)},
1300     {js_InitDateClass,                  EAGER_ATOM_AND_CLASP(Date)},
1301     {js_InitMathClass,                  EAGER_ATOM_AND_CLASP(Math)},
1302     {js_InitNumberClass,                EAGER_ATOM_AND_CLASP(Number)},
1303     {js_InitStringClass,                EAGER_ATOM_AND_CLASP(String)},
1304     {js_InitCallClass,                  EAGER_ATOM_AND_CLASP(Call)},
1305     {js_InitExceptionClasses,           EAGER_ATOM_AND_CLASP(Error)},
1306     {js_InitRegExpClass,                EAGER_ATOM_AND_CLASP(RegExp)},
1307 #if JS_HAS_SCRIPT_OBJECT
1308     {js_InitScriptClass,                EAGER_ATOM_AND_CLASP(Script)},
1309 #endif
1310 #if JS_HAS_XML_SUPPORT
1311     {js_InitXMLClass,                   EAGER_ATOM_AND_CLASP(XML)},
1312     {js_InitNamespaceClass,             EAGER_ATOM_AND_CLASP(Namespace)},
1313     {js_InitQNameClass,                 EAGER_ATOM_AND_CLASP(QName)},
1314 #endif
1315 #if JS_HAS_FILE_OBJECT
1316     {js_InitFileClass,                  EAGER_ATOM_AND_CLASP(File)},
1317 #endif
1318 #if JS_HAS_GENERATORS
1319     {js_InitIteratorClasses,            EAGER_ATOM_AND_CLASP(StopIteration)},
1320 #endif
1321     {NULL,                              0, NULL, NULL}
1322 };
1323 
1324 /*
1325  * Table of top-level function and constant names and their init functions.
1326  * If you add a "standard" global function or property, remember to update
1327  * this table.
1328  */
1329 static JSStdName standard_class_names[] = {
1330     /* ECMA requires that eval be a direct property of the global object. */
1331     {js_InitObjectClass,        EAGER_ATOM(eval), NULL},
1332 
1333     /* Global properties and functions defined by the Number class. */
1334     {js_InitNumberClass,        LAZY_ATOM(NaN), NULL},
1335     {js_InitNumberClass,        LAZY_ATOM(Infinity), NULL},
1336     {js_InitNumberClass,        LAZY_ATOM(isNaN), NULL},
1337     {js_InitNumberClass,        LAZY_ATOM(isFinite), NULL},
1338     {js_InitNumberClass,        LAZY_ATOM(parseFloat), NULL},
1339     {js_InitNumberClass,        LAZY_ATOM(parseInt), NULL},
1340 
1341     /* String global functions. */
1342     {js_InitStringClass,        LAZY_ATOM(escape), NULL},
1343     {js_InitStringClass,        LAZY_ATOM(unescape), NULL},
1344     {js_InitStringClass,        LAZY_ATOM(decodeURI), NULL},
1345     {js_InitStringClass,        LAZY_ATOM(encodeURI), NULL},
1346     {js_InitStringClass,        LAZY_ATOM(decodeURIComponent), NULL},
1347     {js_InitStringClass,        LAZY_ATOM(encodeURIComponent), NULL},
1348 #if JS_HAS_UNEVAL
1349     {js_InitStringClass,        LAZY_ATOM(uneval), NULL},
1350 #endif
1351 
1352     /* Exception constructors. */
1353     {js_InitExceptionClasses,   EAGER_CLASS_ATOM(Error), CLASP(Error)},
1354     {js_InitExceptionClasses,   EAGER_CLASS_ATOM(InternalError), CLASP(Error)},
1355     {js_InitExceptionClasses,   EAGER_CLASS_ATOM(EvalError), CLASP(Error)},
1356     {js_InitExceptionClasses,   EAGER_CLASS_ATOM(RangeError), CLASP(Error)},
1357     {js_InitExceptionClasses,   EAGER_CLASS_ATOM(ReferenceError), CLASP(Error)},
1358     {js_InitExceptionClasses,   EAGER_CLASS_ATOM(SyntaxError), CLASP(Error)},
1359     {js_InitExceptionClasses,   EAGER_CLASS_ATOM(TypeError), CLASP(Error)},
1360     {js_InitExceptionClasses,   EAGER_CLASS_ATOM(URIError), CLASP(Error)},
1361 
1362 #if JS_HAS_XML_SUPPORT
1363     {js_InitAnyNameClass,       EAGER_ATOM_AND_CLASP(AnyName)},
1364     {js_InitAttributeNameClass, EAGER_ATOM_AND_CLASP(AttributeName)},
1365     {js_InitXMLClass,           LAZY_ATOM(XMLList), &js_XMLClass},
1366     {js_InitXMLClass,           LAZY_ATOM(isXMLName), NULL},
1367 #endif
1368 
1369 #if JS_HAS_GENERATORS
1370     {js_InitIteratorClasses,    EAGER_ATOM_AND_CLASP(Iterator)},
1371     {js_InitIteratorClasses,    EAGER_ATOM_AND_CLASP(Generator)},
1372 #endif
1373 
1374     {NULL,                      0, NULL, NULL}
1375 };
1376 
1377 static JSStdName object_prototype_names[] = {
1378     /* Object.prototype properties (global delegates to Object.prototype). */
1379     {js_InitObjectClass,        EAGER_ATOM(proto), NULL},
1380     {js_InitObjectClass,        EAGER_ATOM(parent), NULL},
1381     {js_InitObjectClass,        EAGER_ATOM(count), NULL},
1382 #if JS_HAS_TOSOURCE
1383     {js_InitObjectClass,        EAGER_ATOM(toSource), NULL},
1384 #endif
1385     {js_InitObjectClass,        EAGER_ATOM(toString), NULL},
1386     {js_InitObjectClass,        EAGER_ATOM(toLocaleString), NULL},
1387     {js_InitObjectClass,        EAGER_ATOM(valueOf), NULL},
1388 #if JS_HAS_OBJ_WATCHPOINT
1389     {js_InitObjectClass,        LAZY_ATOM(watch), NULL},
1390     {js_InitObjectClass,        LAZY_ATOM(unwatch), NULL},
1391 #endif
1392     {js_InitObjectClass,        LAZY_ATOM(hasOwnProperty), NULL},
1393     {js_InitObjectClass,        LAZY_ATOM(isPrototypeOf), NULL},
1394     {js_InitObjectClass,        LAZY_ATOM(propertyIsEnumerable), NULL},
1395 #if JS_HAS_GETTER_SETTER
1396     {js_InitObjectClass,        LAZY_ATOM(defineGetter), NULL},
1397     {js_InitObjectClass,        LAZY_ATOM(defineSetter), NULL},
1398     {js_InitObjectClass,        LAZY_ATOM(lookupGetter), NULL},
1399     {js_InitObjectClass,        LAZY_ATOM(lookupSetter), NULL},
1400 #endif
1401 
1402     {NULL,                      0, NULL, NULL}
1403 };
1404 
1405 JS_PUBLIC_API(JSBool)
JS_ResolveStandardClass(JSContext * cx,JSObject * obj,jsval id,JSBool * resolved)1406 JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id,
1407                         JSBool *resolved)
1408 {
1409     JSString *idstr;
1410     JSRuntime *rt;
1411     JSAtom *atom;
1412     JSStdName *stdnm;
1413     uintN i;
1414 
1415     CHECK_REQUEST(cx);
1416     *resolved = JS_FALSE;
1417 
1418     if (!JSVAL_IS_STRING(id))
1419         return JS_TRUE;
1420     idstr = JSVAL_TO_STRING(id);
1421     rt = cx->runtime;
1422 
1423     /* Check whether we're resolving 'undefined', and define it if so. */
1424     atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1425     if (idstr == ATOM_TO_STRING(atom)) {
1426         *resolved = JS_TRUE;
1427         return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1428                                    NULL, NULL, JSPROP_PERMANENT, NULL);
1429     }
1430 
1431     /* Try for class constructors/prototypes named by well-known atoms. */
1432     stdnm = NULL;
1433     for (i = 0; standard_class_atoms[i].init; i++) {
1434         atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1435         if (idstr == ATOM_TO_STRING(atom)) {
1436             stdnm = &standard_class_atoms[i];
1437             break;
1438         }
1439     }
1440 
1441     if (!stdnm) {
1442         /* Try less frequently used top-level functions and constants. */
1443         for (i = 0; standard_class_names[i].init; i++) {
1444             atom = StdNameToAtom(cx, &standard_class_names[i]);
1445             if (!atom)
1446                 return JS_FALSE;
1447             if (idstr == ATOM_TO_STRING(atom)) {
1448                 stdnm = &standard_class_names[i];
1449                 break;
1450             }
1451         }
1452 
1453         if (!stdnm && !OBJ_GET_PROTO(cx, obj)) {
1454             /*
1455              * Try even less frequently used names delegated from the global
1456              * object to Object.prototype, but only if the Object class hasn't
1457              * yet been initialized.
1458              */
1459             for (i = 0; object_prototype_names[i].init; i++) {
1460                 atom = StdNameToAtom(cx, &object_prototype_names[i]);
1461                 if (!atom)
1462                     return JS_FALSE;
1463                 if (idstr == ATOM_TO_STRING(atom)) {
1464                     stdnm = &standard_class_names[i];
1465                     break;
1466                 }
1467             }
1468         }
1469     }
1470 
1471     if (stdnm) {
1472         /*
1473          * If this standard class is anonymous and obj advertises itself as a
1474          * global object (in order to reserve slots for standard class object
1475          * pointers), then we don't want to resolve by name.
1476          *
1477          * If inversely, either id does not name a class, or id does not name
1478          * an anonymous class, or the global does not reserve slots for class
1479          * objects, then we must call the init hook here.
1480          */
1481         if (stdnm->clasp &&
1482             (stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS) &&
1483             (OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_IS_GLOBAL)) {
1484             return JS_TRUE;
1485         }
1486 
1487         if (!stdnm->init(cx, obj))
1488             return JS_FALSE;
1489         *resolved = JS_TRUE;
1490     }
1491     return JS_TRUE;
1492 }
1493 
1494 static JSBool
AlreadyHasOwnProperty(JSContext * cx,JSObject * obj,JSAtom * atom)1495 AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, JSAtom *atom)
1496 {
1497     JSScopeProperty *sprop;
1498     JSScope *scope;
1499 
1500     JS_ASSERT(OBJ_IS_NATIVE(obj));
1501     JS_LOCK_OBJ(cx, obj);
1502     scope = OBJ_SCOPE(obj);
1503     sprop = SCOPE_GET_PROPERTY(scope, ATOM_TO_JSID(atom));
1504     JS_UNLOCK_SCOPE(cx, scope);
1505     return sprop != NULL;
1506 }
1507 
1508 JS_PUBLIC_API(JSBool)
JS_EnumerateStandardClasses(JSContext * cx,JSObject * obj)1509 JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
1510 {
1511     JSRuntime *rt;
1512     JSAtom *atom;
1513     uintN i;
1514 
1515     CHECK_REQUEST(cx);
1516     rt = cx->runtime;
1517 
1518     /* Check whether we need to bind 'undefined' and define it if so. */
1519     atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1520     if (!AlreadyHasOwnProperty(cx, obj, atom) &&
1521         !OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1522                              NULL, NULL, JSPROP_PERMANENT, NULL)) {
1523         return JS_FALSE;
1524     }
1525 
1526     /* Initialize any classes that have not been resolved yet. */
1527     for (i = 0; standard_class_atoms[i].init; i++) {
1528         atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1529         if (!AlreadyHasOwnProperty(cx, obj, atom) &&
1530             !standard_class_atoms[i].init(cx, obj)) {
1531             return JS_FALSE;
1532         }
1533     }
1534 
1535     return JS_TRUE;
1536 }
1537 
1538 static JSIdArray *
AddAtomToArray(JSContext * cx,JSAtom * atom,JSIdArray * ida,jsint * ip)1539 AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip)
1540 {
1541     jsint i, length;
1542 
1543     i = *ip;
1544     length = ida->length;
1545     if (i >= length) {
1546         ida = js_SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
1547         if (!ida)
1548             return NULL;
1549         JS_ASSERT(i < ida->length);
1550     }
1551     ida->vector[i] = ATOM_TO_JSID(atom);
1552     *ip = i + 1;
1553     return ida;
1554 }
1555 
1556 static JSIdArray *
EnumerateIfResolved(JSContext * cx,JSObject * obj,JSAtom * atom,JSIdArray * ida,jsint * ip,JSBool * foundp)1557 EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida,
1558                     jsint *ip, JSBool *foundp)
1559 {
1560     *foundp = AlreadyHasOwnProperty(cx, obj, atom);
1561     if (*foundp)
1562         ida = AddAtomToArray(cx, atom, ida, ip);
1563     return ida;
1564 }
1565 
1566 JS_PUBLIC_API(JSIdArray *)
JS_EnumerateResolvedStandardClasses(JSContext * cx,JSObject * obj,JSIdArray * ida)1567 JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj,
1568                                     JSIdArray *ida)
1569 {
1570     JSRuntime *rt;
1571     jsint i, j, k;
1572     JSAtom *atom;
1573     JSBool found;
1574     JSObjectOp init;
1575 
1576     CHECK_REQUEST(cx);
1577     rt = cx->runtime;
1578     if (ida) {
1579         i = ida->length;
1580     } else {
1581         ida = js_NewIdArray(cx, 8);
1582         if (!ida)
1583             return NULL;
1584         i = 0;
1585     }
1586 
1587     /* Check whether 'undefined' has been resolved and enumerate it if so. */
1588     atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1589     ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1590     if (!ida)
1591         return NULL;
1592 
1593     /* Enumerate only classes that *have* been resolved. */
1594     for (j = 0; standard_class_atoms[j].init; j++) {
1595         atom = OFFSET_TO_ATOM(rt, standard_class_atoms[j].atomOffset);
1596         ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1597         if (!ida)
1598             return NULL;
1599 
1600         if (found) {
1601             init = standard_class_atoms[j].init;
1602 
1603             for (k = 0; standard_class_names[k].init; k++) {
1604                 if (standard_class_names[k].init == init) {
1605                     atom = StdNameToAtom(cx, &standard_class_names[k]);
1606                     ida = AddAtomToArray(cx, atom, ida, &i);
1607                     if (!ida)
1608                         return NULL;
1609                 }
1610             }
1611 
1612             if (init == js_InitObjectClass) {
1613                 for (k = 0; object_prototype_names[k].init; k++) {
1614                     atom = StdNameToAtom(cx, &object_prototype_names[k]);
1615                     ida = AddAtomToArray(cx, atom, ida, &i);
1616                     if (!ida)
1617                         return NULL;
1618                 }
1619             }
1620         }
1621     }
1622 
1623     /* Trim to exact length via js_SetIdArrayLength. */
1624     return js_SetIdArrayLength(cx, ida, i);
1625 }
1626 
1627 #undef ATOM_OFFSET
1628 #undef CLASS_ATOM_OFFSET
1629 #undef OFFSET_TO_ATOM
1630 #undef CLASP
1631 
1632 #undef EAGER_ATOM
1633 #undef EAGER_CLASS_ATOM
1634 #undef EAGER_ATOM_CLASP
1635 #undef LAZY_ATOM
1636 
1637 JS_PUBLIC_API(JSBool)
JS_GetClassObject(JSContext * cx,JSObject * obj,JSProtoKey key,JSObject ** objp)1638 JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key,
1639                   JSObject **objp)
1640 {
1641     CHECK_REQUEST(cx);
1642     return js_GetClassObject(cx, obj, key, objp);
1643 }
1644 
1645 JS_PUBLIC_API(JSObject *)
JS_GetScopeChain(JSContext * cx)1646 JS_GetScopeChain(JSContext *cx)
1647 {
1648     JSStackFrame *fp;
1649 
1650     fp = cx->fp;
1651     if (!fp) {
1652         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE);
1653         return NULL;
1654     }
1655     return js_GetScopeChain(cx, fp);
1656 }
1657 
1658 JS_PUBLIC_API(void *)
JS_malloc(JSContext * cx,size_t nbytes)1659 JS_malloc(JSContext *cx, size_t nbytes)
1660 {
1661     void *p;
1662 
1663     JS_ASSERT(nbytes != 0);
1664     if (nbytes == 0)
1665         nbytes = 1;
1666 
1667     p = malloc(nbytes);
1668     if (!p) {
1669         JS_ReportOutOfMemory(cx);
1670         return NULL;
1671     }
1672     js_UpdateMallocCounter(cx, nbytes);
1673 
1674     return p;
1675 }
1676 
1677 JS_PUBLIC_API(void *)
JS_realloc(JSContext * cx,void * p,size_t nbytes)1678 JS_realloc(JSContext *cx, void *p, size_t nbytes)
1679 {
1680     p = realloc(p, nbytes);
1681     if (!p)
1682         JS_ReportOutOfMemory(cx);
1683     return p;
1684 }
1685 
1686 JS_PUBLIC_API(void)
JS_free(JSContext * cx,void * p)1687 JS_free(JSContext *cx, void *p)
1688 {
1689     if (p)
1690         free(p);
1691 }
1692 
1693 JS_PUBLIC_API(char *)
JS_strdup(JSContext * cx,const char * s)1694 JS_strdup(JSContext *cx, const char *s)
1695 {
1696     size_t n;
1697     void *p;
1698 
1699     n = strlen(s) + 1;
1700     p = JS_malloc(cx, n);
1701     if (!p)
1702         return NULL;
1703     return (char *)memcpy(p, s, n);
1704 }
1705 
1706 JS_PUBLIC_API(jsdouble *)
JS_NewDouble(JSContext * cx,jsdouble d)1707 JS_NewDouble(JSContext *cx, jsdouble d)
1708 {
1709     CHECK_REQUEST(cx);
1710     return js_NewDouble(cx, d, 0);
1711 }
1712 
1713 JS_PUBLIC_API(JSBool)
JS_NewDoubleValue(JSContext * cx,jsdouble d,jsval * rval)1714 JS_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval)
1715 {
1716     CHECK_REQUEST(cx);
1717     return js_NewDoubleValue(cx, d, rval);
1718 }
1719 
1720 JS_PUBLIC_API(JSBool)
JS_NewNumberValue(JSContext * cx,jsdouble d,jsval * rval)1721 JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
1722 {
1723     CHECK_REQUEST(cx);
1724     return js_NewNumberValue(cx, d, rval);
1725 }
1726 
1727 #undef JS_AddRoot
1728 JS_PUBLIC_API(JSBool)
JS_AddRoot(JSContext * cx,void * rp)1729 JS_AddRoot(JSContext *cx, void *rp)
1730 {
1731     CHECK_REQUEST(cx);
1732     return js_AddRoot(cx, rp, NULL);
1733 }
1734 
1735 JS_PUBLIC_API(JSBool)
JS_AddNamedRootRT(JSRuntime * rt,void * rp,const char * name)1736 JS_AddNamedRootRT(JSRuntime *rt, void *rp, const char *name)
1737 {
1738     return js_AddRootRT(rt, rp, name);
1739 }
1740 
1741 JS_PUBLIC_API(JSBool)
JS_RemoveRoot(JSContext * cx,void * rp)1742 JS_RemoveRoot(JSContext *cx, void *rp)
1743 {
1744     CHECK_REQUEST(cx);
1745     return js_RemoveRoot(cx->runtime, rp);
1746 }
1747 
1748 JS_PUBLIC_API(JSBool)
JS_RemoveRootRT(JSRuntime * rt,void * rp)1749 JS_RemoveRootRT(JSRuntime *rt, void *rp)
1750 {
1751     return js_RemoveRoot(rt, rp);
1752 }
1753 
1754 JS_PUBLIC_API(JSBool)
JS_AddNamedRoot(JSContext * cx,void * rp,const char * name)1755 JS_AddNamedRoot(JSContext *cx, void *rp, const char *name)
1756 {
1757     CHECK_REQUEST(cx);
1758     return js_AddRoot(cx, rp, name);
1759 }
1760 
1761 JS_PUBLIC_API(void)
JS_ClearNewbornRoots(JSContext * cx)1762 JS_ClearNewbornRoots(JSContext *cx)
1763 {
1764     JS_CLEAR_WEAK_ROOTS(&cx->weakRoots);
1765 }
1766 
1767 JS_PUBLIC_API(JSBool)
JS_EnterLocalRootScope(JSContext * cx)1768 JS_EnterLocalRootScope(JSContext *cx)
1769 {
1770     CHECK_REQUEST(cx);
1771     return js_EnterLocalRootScope(cx);
1772 }
1773 
1774 JS_PUBLIC_API(void)
JS_LeaveLocalRootScope(JSContext * cx)1775 JS_LeaveLocalRootScope(JSContext *cx)
1776 {
1777     CHECK_REQUEST(cx);
1778     js_LeaveLocalRootScope(cx);
1779 }
1780 
1781 JS_PUBLIC_API(void)
JS_LeaveLocalRootScopeWithResult(JSContext * cx,jsval rval)1782 JS_LeaveLocalRootScopeWithResult(JSContext *cx, jsval rval)
1783 {
1784     CHECK_REQUEST(cx);
1785     js_LeaveLocalRootScopeWithResult(cx, rval);
1786 }
1787 
1788 JS_PUBLIC_API(void)
JS_ForgetLocalRoot(JSContext * cx,void * thing)1789 JS_ForgetLocalRoot(JSContext *cx, void *thing)
1790 {
1791     CHECK_REQUEST(cx);
1792     js_ForgetLocalRoot(cx, (jsval) thing);
1793 }
1794 
1795 #ifdef DEBUG
1796 
1797 JS_PUBLIC_API(void)
JS_DumpNamedRoots(JSRuntime * rt,void (* dump)(const char * name,void * rp,void * data),void * data)1798 JS_DumpNamedRoots(JSRuntime *rt,
1799                   void (*dump)(const char *name, void *rp, void *data),
1800                   void *data)
1801 {
1802     js_DumpNamedRoots(rt, dump, data);
1803 }
1804 
1805 #endif /* DEBUG */
1806 
1807 JS_PUBLIC_API(uint32)
JS_MapGCRoots(JSRuntime * rt,JSGCRootMapFun map,void * data)1808 JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
1809 {
1810     return js_MapGCRoots(rt, map, data);
1811 }
1812 
1813 JS_PUBLIC_API(JSBool)
JS_LockGCThing(JSContext * cx,void * thing)1814 JS_LockGCThing(JSContext *cx, void *thing)
1815 {
1816     JSBool ok;
1817 
1818     CHECK_REQUEST(cx);
1819     ok = js_LockGCThing(cx, thing);
1820     if (!ok)
1821         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_LOCK);
1822     return ok;
1823 }
1824 
1825 JS_PUBLIC_API(JSBool)
JS_LockGCThingRT(JSRuntime * rt,void * thing)1826 JS_LockGCThingRT(JSRuntime *rt, void *thing)
1827 {
1828     return js_LockGCThingRT(rt, thing);
1829 }
1830 
1831 JS_PUBLIC_API(JSBool)
JS_UnlockGCThing(JSContext * cx,void * thing)1832 JS_UnlockGCThing(JSContext *cx, void *thing)
1833 {
1834     JSBool ok;
1835 
1836     CHECK_REQUEST(cx);
1837     ok = js_UnlockGCThingRT(cx->runtime, thing);
1838     if (!ok)
1839         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_UNLOCK);
1840     return ok;
1841 }
1842 
1843 JS_PUBLIC_API(JSBool)
JS_UnlockGCThingRT(JSRuntime * rt,void * thing)1844 JS_UnlockGCThingRT(JSRuntime *rt, void *thing)
1845 {
1846     return js_UnlockGCThingRT(rt, thing);
1847 }
1848 
1849 JS_PUBLIC_API(void)
JS_MarkGCThing(JSContext * cx,void * thing,const char * name,void * arg)1850 JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg)
1851 {
1852     JS_ASSERT(cx->runtime->gcLevel > 0);
1853 #ifdef JS_THREADSAFE
1854     JS_ASSERT(cx->runtime->gcThread->id == js_CurrentThreadId());
1855 #endif
1856 
1857     GC_MARK(cx, thing, name);
1858 }
1859 
1860 JS_PUBLIC_API(void)
JS_GC(JSContext * cx)1861 JS_GC(JSContext *cx)
1862 {
1863 #if JS_HAS_GENERATORS
1864     /* Run previously scheduled but delayed close hooks. */
1865     js_RunCloseHooks(cx);
1866 #endif
1867 
1868     /* Don't nuke active arenas if executing or compiling. */
1869     if (cx->stackPool.current == &cx->stackPool.first)
1870         JS_FinishArenaPool(&cx->stackPool);
1871     if (cx->tempPool.current == &cx->tempPool.first)
1872         JS_FinishArenaPool(&cx->tempPool);
1873     js_GC(cx, GC_NORMAL);
1874 
1875 #if JS_HAS_GENERATORS
1876     /*
1877      * Run close hooks for objects that became unreachable after the last GC.
1878      */
1879     js_RunCloseHooks(cx);
1880 #endif
1881 }
1882 
1883 JS_PUBLIC_API(void)
JS_MaybeGC(JSContext * cx)1884 JS_MaybeGC(JSContext *cx)
1885 {
1886 #ifdef WAY_TOO_MUCH_GC
1887     JS_GC(cx);
1888 #else
1889     JSRuntime *rt;
1890     uint32 bytes, lastBytes;
1891 
1892     rt = cx->runtime;
1893     bytes = rt->gcBytes;
1894     lastBytes = rt->gcLastBytes;
1895 
1896     /*
1897      * We run the GC if we used all available free GC cells and had to
1898      * allocate extra 1/5 of GC arenas since the last run of GC, or if
1899      * we have malloc'd more bytes through JS_malloc than we were told
1900      * to allocate by JS_NewRuntime.
1901      *
1902      * The reason for
1903      *   bytes > 6/5 lastBytes
1904      * condition is the following. Bug 312238 changed bytes and lastBytes
1905      * to mean the total amount of memory that the GC uses now and right
1906      * after the last GC.
1907      *
1908      * Before the bug the variables meant the size of allocated GC things
1909      * now and right after the last GC. That size did not include the
1910      * memory taken by free GC cells and the condition was
1911      *   bytes > 3/2 lastBytes.
1912      * That is, we run the GC if we have half again as many bytes of
1913      * GC-things as the last time we GC'd. To be compatible we need to
1914      * express that condition through the new meaning of bytes and
1915      * lastBytes.
1916      *
1917      * We write the original condition as
1918      *   B*(1-F) > 3/2 Bl*(1-Fl)
1919      * where B is the total memory size allocated by GC and F is the free
1920      * cell density currently and Sl and Fl are the size and the density
1921      * right after GC. The density by definition is memory taken by free
1922      * cells divided by total amount of memory. In other words, B and Bl
1923      * are bytes and lastBytes with the new meaning and B*(1-F) and
1924      * Bl*(1-Fl) are bytes and lastBytes with the original meaning.
1925      *
1926      * Our task is to exclude F and Fl from the last statement. According
1927      * the stats from bug 331770 Fl is about 20-30% for GC allocations
1928      * that contribute to S and Sl for a typical run of the browser. It
1929      * means that the original condition implied that we did not run GC
1930      * unless we exhausted the pool of free cells. Indeed if we still
1931      * have free cells, then B == Bl since we did not yet allocated any
1932      * new arenas and the condition means
1933      *   1 - F > 3/2 (1-Fl) or 3/2Fl > 1/2 + F
1934      * That implies 3/2 Fl > 1/2 or Fl > 1/3. That can not be fulfilled
1935      * for the state described by the stats. So we can write the original
1936      * condition as:
1937      *   F == 0 && B > 3/2 Bl(1-Fl)
1938      * Again using the stats we see that Fl is about 20% when the browser
1939      * starts up and when we are far from hitting rt->gcMaxBytes. With
1940      * this F we have
1941      * F == 0 && B > 3/2 Bl(1-0.8) or just B > 6/5 Bl.
1942      */
1943     if ((bytes > 8192 && bytes > lastBytes + lastBytes / 5) ||
1944         rt->gcMallocBytes >= rt->gcMaxMallocBytes) {
1945         JS_GC(cx);
1946     }
1947 #if JS_HAS_GENERATORS
1948     else {
1949         /* Run scheduled but not yet executed close hooks. */
1950         js_RunCloseHooks(cx);
1951     }
1952 #endif
1953 #endif
1954 }
1955 
1956 JS_PUBLIC_API(JSGCCallback)
JS_SetGCCallback(JSContext * cx,JSGCCallback cb)1957 JS_SetGCCallback(JSContext *cx, JSGCCallback cb)
1958 {
1959     return JS_SetGCCallbackRT(cx->runtime, cb);
1960 }
1961 
1962 JS_PUBLIC_API(JSGCCallback)
JS_SetGCCallbackRT(JSRuntime * rt,JSGCCallback cb)1963 JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb)
1964 {
1965     JSGCCallback oldcb;
1966 
1967     oldcb = rt->gcCallback;
1968     rt->gcCallback = cb;
1969     return oldcb;
1970 }
1971 
1972 JS_PUBLIC_API(JSBool)
JS_IsAboutToBeFinalized(JSContext * cx,void * thing)1973 JS_IsAboutToBeFinalized(JSContext *cx, void *thing)
1974 {
1975     JS_ASSERT(thing);
1976     return js_IsAboutToBeFinalized(cx, thing);
1977 }
1978 
1979 JS_PUBLIC_API(void)
JS_SetGCParameter(JSRuntime * rt,JSGCParamKey key,uint32 value)1980 JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value)
1981 {
1982     switch (key) {
1983       case JSGC_MAX_BYTES:
1984         rt->gcMaxBytes = value;
1985         break;
1986       case JSGC_MAX_MALLOC_BYTES:
1987         rt->gcMaxMallocBytes = value;
1988         break;
1989     }
1990 }
1991 
1992 JS_PUBLIC_API(intN)
JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer)1993 JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer)
1994 {
1995     return js_ChangeExternalStringFinalizer(NULL, finalizer);
1996 }
1997 
1998 JS_PUBLIC_API(intN)
JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer)1999 JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer)
2000 {
2001     return js_ChangeExternalStringFinalizer(finalizer, NULL);
2002 }
2003 
2004 JS_PUBLIC_API(JSString *)
JS_NewExternalString(JSContext * cx,jschar * chars,size_t length,intN type)2005 JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
2006 {
2007     JSString *str;
2008 
2009     CHECK_REQUEST(cx);
2010     JS_ASSERT(GCX_EXTERNAL_STRING <= type && type < (intN) GCX_NTYPES);
2011 
2012     str = (JSString *) js_NewGCThing(cx, (uintN) type, sizeof(JSString));
2013     if (!str)
2014         return NULL;
2015     str->length = length;
2016     str->chars = chars;
2017     return str;
2018 }
2019 
2020 JS_PUBLIC_API(intN)
JS_GetExternalStringGCType(JSRuntime * rt,JSString * str)2021 JS_GetExternalStringGCType(JSRuntime *rt, JSString *str)
2022 {
2023     uint8 type = (uint8) (*js_GetGCThingFlags(str) & GCF_TYPEMASK);
2024 
2025     if (type >= GCX_EXTERNAL_STRING)
2026         return (intN)type;
2027     JS_ASSERT(type == GCX_STRING || type == GCX_MUTABLE_STRING);
2028     return -1;
2029 }
2030 
2031 JS_PUBLIC_API(void)
JS_SetThreadStackLimit(JSContext * cx,jsuword limitAddr)2032 JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr)
2033 {
2034 #if JS_STACK_GROWTH_DIRECTION > 0
2035     if (limitAddr == 0)
2036         limitAddr = (jsuword)-1;
2037 #endif
2038     cx->stackLimit = limitAddr;
2039 }
2040 
2041 /************************************************************************/
2042 
2043 JS_PUBLIC_API(void)
JS_DestroyIdArray(JSContext * cx,JSIdArray * ida)2044 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
2045 {
2046     JS_free(cx, ida);
2047 }
2048 
2049 JS_PUBLIC_API(JSBool)
JS_ValueToId(JSContext * cx,jsval v,jsid * idp)2050 JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
2051 {
2052     JSAtom *atom;
2053 
2054     CHECK_REQUEST(cx);
2055     if (JSVAL_IS_INT(v)) {
2056         *idp = INT_JSVAL_TO_JSID(v);
2057     } else {
2058 #if JS_HAS_XML_SUPPORT
2059         if (JSVAL_IS_OBJECT(v)) {
2060             *idp = OBJECT_JSVAL_TO_JSID(v);
2061             return JS_TRUE;
2062         }
2063 #endif
2064         atom = js_ValueToStringAtom(cx, v);
2065         if (!atom)
2066             return JS_FALSE;
2067         *idp = ATOM_TO_JSID(atom);
2068     }
2069     return JS_TRUE;
2070 }
2071 
2072 JS_PUBLIC_API(JSBool)
JS_IdToValue(JSContext * cx,jsid id,jsval * vp)2073 JS_IdToValue(JSContext *cx, jsid id, jsval *vp)
2074 {
2075     CHECK_REQUEST(cx);
2076     *vp = ID_TO_VALUE(id);
2077     return JS_TRUE;
2078 }
2079 
2080 JS_PUBLIC_API(JSBool)
JS_PropertyStub(JSContext * cx,JSObject * obj,jsval id,jsval * vp)2081 JS_PropertyStub(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
2082 {
2083     return JS_TRUE;
2084 }
2085 
2086 JS_PUBLIC_API(JSBool)
JS_EnumerateStub(JSContext * cx,JSObject * obj)2087 JS_EnumerateStub(JSContext *cx, JSObject *obj)
2088 {
2089     return JS_TRUE;
2090 }
2091 
2092 JS_PUBLIC_API(JSBool)
JS_ResolveStub(JSContext * cx,JSObject * obj,jsval id)2093 JS_ResolveStub(JSContext *cx, JSObject *obj, jsval id)
2094 {
2095     return JS_TRUE;
2096 }
2097 
2098 JS_PUBLIC_API(JSBool)
JS_ConvertStub(JSContext * cx,JSObject * obj,JSType type,jsval * vp)2099 JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
2100 {
2101     return js_TryValueOf(cx, obj, type, vp);
2102 }
2103 
2104 JS_PUBLIC_API(void)
JS_FinalizeStub(JSContext * cx,JSObject * obj)2105 JS_FinalizeStub(JSContext *cx, JSObject *obj)
2106 {
2107 }
2108 
2109 JS_PUBLIC_API(JSObject *)
JS_InitClass(JSContext * cx,JSObject * obj,JSObject * parent_proto,JSClass * clasp,JSNative constructor,uintN nargs,JSPropertySpec * ps,JSFunctionSpec * fs,JSPropertySpec * static_ps,JSFunctionSpec * static_fs)2110 JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
2111              JSClass *clasp, JSNative constructor, uintN nargs,
2112              JSPropertySpec *ps, JSFunctionSpec *fs,
2113              JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
2114 {
2115     JSAtom *atom;
2116     JSProtoKey key;
2117     JSObject *proto, *ctor;
2118     JSTempValueRooter tvr;
2119     jsval cval, rval;
2120     JSBool named;
2121     JSFunction *fun;
2122 
2123     CHECK_REQUEST(cx);
2124     atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0);
2125     if (!atom)
2126         return NULL;
2127 
2128     /*
2129      * When initializing a standard class, if no parent_proto (grand-proto of
2130      * instances of the class, parent-proto of the class's prototype object)
2131      * is given, we must use Object.prototype if it is available.  Otherwise,
2132      * we could look up the wrong binding for a class name in obj.  Example:
2133      *
2134      *   String = Array;
2135      *   print("hi there".join);
2136      *
2137      * should print undefined, not Array.prototype.join.  This is required by
2138      * ECMA-262, alas.  It might have been better to make String readonly and
2139      * permanent in the global object, instead -- but that's too big a change
2140      * to swallow at this point.
2141      */
2142     key = JSCLASS_CACHED_PROTO_KEY(clasp);
2143     if (key != JSProto_Null &&
2144         !parent_proto &&
2145         !js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Object),
2146                               &parent_proto)) {
2147         return NULL;
2148     }
2149 
2150     /* Create a prototype object for this class. */
2151     proto = js_NewObject(cx, clasp, parent_proto, obj);
2152     if (!proto)
2153         return NULL;
2154 
2155     /* After this point, control must exit via label bad or out. */
2156     JS_PUSH_TEMP_ROOT_OBJECT(cx, proto, &tvr);
2157 
2158     if (!constructor) {
2159         /*
2160          * Lacking a constructor, name the prototype (e.g., Math) unless this
2161          * class (a) is anonymous, i.e. for internal use only; (b) the class
2162          * of obj (the global object) is has a reserved slot indexed by key;
2163          * and (c) key is not the null key.
2164          */
2165         if ((clasp->flags & JSCLASS_IS_ANONYMOUS) &&
2166             (OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_IS_GLOBAL) &&
2167             key != JSProto_Null) {
2168             named = JS_FALSE;
2169         } else {
2170             named = OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom),
2171                                         OBJECT_TO_JSVAL(proto),
2172                                         NULL, NULL,
2173                                         (clasp->flags & JSCLASS_IS_ANONYMOUS)
2174                                         ? JSPROP_READONLY | JSPROP_PERMANENT
2175                                         : 0,
2176                                         NULL);
2177             if (!named)
2178                 goto bad;
2179         }
2180 
2181         ctor = proto;
2182     } else {
2183         /* Define the constructor function in obj's scope. */
2184         fun = js_DefineFunction(cx, obj, atom, constructor, nargs, 0);
2185         named = (fun != NULL);
2186         if (!fun)
2187             goto bad;
2188 
2189         /*
2190          * Remember the class this function is a constructor for so that
2191          * we know to create an object of this class when we call the
2192          * constructor.
2193          */
2194         fun->clasp = clasp;
2195 
2196         /*
2197          * Optionally construct the prototype object, before the class has
2198          * been fully initialized.  Allow the ctor to replace proto with a
2199          * different object, as is done for operator new -- and as at least
2200          * XML support requires.
2201          */
2202         ctor = fun->object;
2203         if (clasp->flags & JSCLASS_CONSTRUCT_PROTOTYPE) {
2204             cval = OBJECT_TO_JSVAL(ctor);
2205             if (!js_InternalConstruct(cx, proto, cval, 0, NULL, &rval))
2206                 goto bad;
2207             if (!JSVAL_IS_PRIMITIVE(rval) && JSVAL_TO_OBJECT(rval) != proto)
2208                 proto = JSVAL_TO_OBJECT(rval);
2209         }
2210 
2211         /* Connect constructor and prototype by named properties. */
2212         if (!js_SetClassPrototype(cx, ctor, proto,
2213                                   JSPROP_READONLY | JSPROP_PERMANENT)) {
2214             goto bad;
2215         }
2216 
2217         /* Bootstrap Function.prototype (see also JS_InitStandardClasses). */
2218         if (OBJ_GET_CLASS(cx, ctor) == clasp) {
2219             JS_ASSERT(!OBJ_GET_PROTO(cx, ctor));
2220             OBJ_SET_PROTO(cx, ctor, proto);
2221         }
2222     }
2223 
2224     /* Add properties and methods to the prototype and the constructor. */
2225     if ((ps && !JS_DefineProperties(cx, proto, ps)) ||
2226         (fs && !JS_DefineFunctions(cx, proto, fs)) ||
2227         (static_ps && !JS_DefineProperties(cx, ctor, static_ps)) ||
2228         (static_fs && !JS_DefineFunctions(cx, ctor, static_fs))) {
2229         goto bad;
2230     }
2231 
2232     /* If this is a standard class, cache its prototype. */
2233     if (key != JSProto_Null && !js_SetClassObject(cx, obj, key, ctor))
2234         goto bad;
2235 
2236 out:
2237     JS_POP_TEMP_ROOT(cx, &tvr);
2238     return proto;
2239 
2240 bad:
2241     if (named)
2242         (void) OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &rval);
2243     proto = NULL;
2244     goto out;
2245 }
2246 
2247 #ifdef JS_THREADSAFE
2248 JS_PUBLIC_API(JSClass *)
JS_GetClass(JSContext * cx,JSObject * obj)2249 JS_GetClass(JSContext *cx, JSObject *obj)
2250 {
2251     return (JSClass *)
2252         JSVAL_TO_PRIVATE(GC_AWARE_GET_SLOT(cx, obj, JSSLOT_CLASS));
2253 }
2254 #else
2255 JS_PUBLIC_API(JSClass *)
JS_GetClass(JSObject * obj)2256 JS_GetClass(JSObject *obj)
2257 {
2258     return LOCKED_OBJ_GET_CLASS(obj);
2259 }
2260 #endif
2261 
2262 JS_PUBLIC_API(JSBool)
JS_InstanceOf(JSContext * cx,JSObject * obj,JSClass * clasp,jsval * argv)2263 JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
2264 {
2265     JSFunction *fun;
2266 
2267     CHECK_REQUEST(cx);
2268     if (OBJ_GET_CLASS(cx, obj) == clasp)
2269         return JS_TRUE;
2270     if (argv) {
2271         fun = js_ValueToFunction(cx, &argv[-2], 0);
2272         if (fun) {
2273             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2274                                  JSMSG_INCOMPATIBLE_PROTO,
2275                                  clasp->name, JS_GetFunctionName(fun),
2276                                  OBJ_GET_CLASS(cx, obj)->name);
2277         }
2278     }
2279     return JS_FALSE;
2280 }
2281 
2282 JS_PUBLIC_API(JSBool)
JS_HasInstance(JSContext * cx,JSObject * obj,jsval v,JSBool * bp)2283 JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
2284 {
2285     return js_HasInstance(cx, obj, v, bp);
2286 }
2287 
2288 JS_PUBLIC_API(void *)
JS_GetPrivate(JSContext * cx,JSObject * obj)2289 JS_GetPrivate(JSContext *cx, JSObject *obj)
2290 {
2291     jsval v;
2292 
2293     JS_ASSERT(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE);
2294     v = GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
2295     if (!JSVAL_IS_INT(v))
2296         return NULL;
2297     return JSVAL_TO_PRIVATE(v);
2298 }
2299 
2300 JS_PUBLIC_API(JSBool)
JS_SetPrivate(JSContext * cx,JSObject * obj,void * data)2301 JS_SetPrivate(JSContext *cx, JSObject *obj, void *data)
2302 {
2303     JS_ASSERT(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE);
2304     OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(data));
2305     return JS_TRUE;
2306 }
2307 
2308 JS_PUBLIC_API(void *)
JS_GetInstancePrivate(JSContext * cx,JSObject * obj,JSClass * clasp,jsval * argv)2309 JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp,
2310                       jsval *argv)
2311 {
2312     if (!JS_InstanceOf(cx, obj, clasp, argv))
2313         return NULL;
2314     return JS_GetPrivate(cx, obj);
2315 }
2316 
2317 JS_PUBLIC_API(JSObject *)
JS_GetPrototype(JSContext * cx,JSObject * obj)2318 JS_GetPrototype(JSContext *cx, JSObject *obj)
2319 {
2320     JSObject *proto;
2321 
2322     CHECK_REQUEST(cx);
2323     proto = JSVAL_TO_OBJECT(GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PROTO));
2324 
2325     /* Beware ref to dead object (we may be called from obj's finalizer). */
2326     return proto && proto->map ? proto : NULL;
2327 }
2328 
2329 JS_PUBLIC_API(JSBool)
JS_SetPrototype(JSContext * cx,JSObject * obj,JSObject * proto)2330 JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto)
2331 {
2332     CHECK_REQUEST(cx);
2333     if (obj->map->ops->setProto)
2334         return obj->map->ops->setProto(cx, obj, JSSLOT_PROTO, proto);
2335     OBJ_SET_SLOT(cx, obj, JSSLOT_PROTO, OBJECT_TO_JSVAL(proto));
2336     return JS_TRUE;
2337 }
2338 
2339 JS_PUBLIC_API(JSObject *)
JS_GetParent(JSContext * cx,JSObject * obj)2340 JS_GetParent(JSContext *cx, JSObject *obj)
2341 {
2342     JSObject *parent;
2343 
2344     parent = JSVAL_TO_OBJECT(GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PARENT));
2345 
2346     /* Beware ref to dead object (we may be called from obj's finalizer). */
2347     return parent && parent->map ? parent : NULL;
2348 }
2349 
2350 JS_PUBLIC_API(JSBool)
JS_SetParent(JSContext * cx,JSObject * obj,JSObject * parent)2351 JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
2352 {
2353     CHECK_REQUEST(cx);
2354     if (obj->map->ops->setParent)
2355         return obj->map->ops->setParent(cx, obj, JSSLOT_PARENT, parent);
2356     OBJ_SET_SLOT(cx, obj, JSSLOT_PARENT, OBJECT_TO_JSVAL(parent));
2357     return JS_TRUE;
2358 }
2359 
2360 JS_PUBLIC_API(JSObject *)
JS_GetConstructor(JSContext * cx,JSObject * proto)2361 JS_GetConstructor(JSContext *cx, JSObject *proto)
2362 {
2363     jsval cval;
2364 
2365     CHECK_REQUEST(cx);
2366     if (!OBJ_GET_PROPERTY(cx, proto,
2367                           ATOM_TO_JSID(cx->runtime->atomState.constructorAtom),
2368                           &cval)) {
2369         return NULL;
2370     }
2371     if (!VALUE_IS_FUNCTION(cx, cval)) {
2372         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR,
2373                              OBJ_GET_CLASS(cx, proto)->name);
2374         return NULL;
2375     }
2376     return JSVAL_TO_OBJECT(cval);
2377 }
2378 
2379 JS_PUBLIC_API(JSBool)
JS_GetObjectId(JSContext * cx,JSObject * obj,jsid * idp)2380 JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
2381 {
2382     JS_ASSERT(((jsid)obj & JSID_TAGMASK) == 0);
2383     *idp = OBJECT_TO_JSID(obj);
2384     return JS_TRUE;
2385 }
2386 
2387 JS_PUBLIC_API(JSObject *)
JS_NewObject(JSContext * cx,JSClass * clasp,JSObject * proto,JSObject * parent)2388 JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
2389 {
2390     CHECK_REQUEST(cx);
2391     if (!clasp)
2392         clasp = &js_ObjectClass;    /* default class is Object */
2393     return js_NewObject(cx, clasp, proto, parent);
2394 }
2395 
2396 JS_PUBLIC_API(JSBool)
JS_SealObject(JSContext * cx,JSObject * obj,JSBool deep)2397 JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep)
2398 {
2399     JSScope *scope;
2400     JSIdArray *ida;
2401     uint32 nslots;
2402     jsval v, *vp, *end;
2403 
2404     if (!OBJ_IS_NATIVE(obj)) {
2405         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2406                              JSMSG_CANT_SEAL_OBJECT,
2407                              OBJ_GET_CLASS(cx, obj)->name);
2408         return JS_FALSE;
2409     }
2410 
2411     scope = OBJ_SCOPE(obj);
2412 
2413 #if defined JS_THREADSAFE && defined DEBUG
2414     /* Insist on scope being used exclusively by cx's thread. */
2415     if (scope->ownercx != cx) {
2416         JS_LOCK_OBJ(cx, obj);
2417         JS_ASSERT(OBJ_SCOPE(obj) == scope);
2418         JS_ASSERT(scope->ownercx == cx);
2419         JS_UNLOCK_SCOPE(cx, scope);
2420     }
2421 #endif
2422 
2423     /* Nothing to do if obj's scope is already sealed. */
2424     if (SCOPE_IS_SEALED(scope))
2425         return JS_TRUE;
2426 
2427     /* XXX Enumerate lazy properties now, as they can't be added later. */
2428     ida = JS_Enumerate(cx, obj);
2429     if (!ida)
2430         return JS_FALSE;
2431     JS_DestroyIdArray(cx, ida);
2432 
2433     /* Ensure that obj has its own, mutable scope, and seal that scope. */
2434     JS_LOCK_OBJ(cx, obj);
2435     scope = js_GetMutableScope(cx, obj);
2436     if (scope)
2437         SCOPE_SET_SEALED(scope);
2438     JS_UNLOCK_OBJ(cx, obj);
2439     if (!scope)
2440         return JS_FALSE;
2441 
2442     /* If we are not sealing an entire object graph, we're done. */
2443     if (!deep)
2444         return JS_TRUE;
2445 
2446     /* Walk obj->slots and if any value is a non-null object, seal it. */
2447     nslots = JS_MIN(scope->map.freeslot, scope->map.nslots);
2448     for (vp = obj->slots, end = vp + nslots; vp < end; vp++) {
2449         v = *vp;
2450         if (JSVAL_IS_PRIMITIVE(v))
2451             continue;
2452         if (!JS_SealObject(cx, JSVAL_TO_OBJECT(v), deep))
2453             return JS_FALSE;
2454     }
2455     return JS_TRUE;
2456 }
2457 
2458 JS_PUBLIC_API(JSObject *)
JS_ConstructObject(JSContext * cx,JSClass * clasp,JSObject * proto,JSObject * parent)2459 JS_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
2460                    JSObject *parent)
2461 {
2462     CHECK_REQUEST(cx);
2463     if (!clasp)
2464         clasp = &js_ObjectClass;    /* default class is Object */
2465     return js_ConstructObject(cx, clasp, proto, parent, 0, NULL);
2466 }
2467 
2468 JS_PUBLIC_API(JSObject *)
JS_ConstructObjectWithArguments(JSContext * cx,JSClass * clasp,JSObject * proto,JSObject * parent,uintN argc,jsval * argv)2469 JS_ConstructObjectWithArguments(JSContext *cx, JSClass *clasp, JSObject *proto,
2470                                 JSObject *parent, uintN argc, jsval *argv)
2471 {
2472     CHECK_REQUEST(cx);
2473     if (!clasp)
2474         clasp = &js_ObjectClass;    /* default class is Object */
2475     return js_ConstructObject(cx, clasp, proto, parent, argc, argv);
2476 }
2477 
2478 static JSBool
DefineProperty(JSContext * cx,JSObject * obj,const char * name,jsval value,JSPropertyOp getter,JSPropertyOp setter,uintN attrs,uintN flags,intN tinyid)2479 DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
2480                JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
2481                uintN flags, intN tinyid)
2482 {
2483     jsid id;
2484     JSAtom *atom;
2485 
2486     if (attrs & JSPROP_INDEX) {
2487         id = INT_TO_JSID(JS_PTR_TO_INT32(name));
2488         atom = NULL;
2489         attrs &= ~JSPROP_INDEX;
2490     } else {
2491         atom = js_Atomize(cx, name, strlen(name), 0);
2492         if (!atom)
2493             return JS_FALSE;
2494         id = ATOM_TO_JSID(atom);
2495     }
2496     if (flags != 0 && OBJ_IS_NATIVE(obj)) {
2497         return js_DefineNativeProperty(cx, obj, id, value, getter, setter,
2498                                        attrs, flags, tinyid, NULL);
2499     }
2500     return OBJ_DEFINE_PROPERTY(cx, obj, id, value, getter, setter, attrs,
2501                                NULL);
2502 }
2503 
2504 #define AUTO_NAMELEN(s,n)   (((n) == (size_t)-1) ? js_strlen(s) : (n))
2505 
2506 static JSBool
DefineUCProperty(JSContext * cx,JSObject * obj,const jschar * name,size_t namelen,jsval value,JSPropertyOp getter,JSPropertyOp setter,uintN attrs,uintN flags,intN tinyid)2507 DefineUCProperty(JSContext *cx, JSObject *obj,
2508                  const jschar *name, size_t namelen, jsval value,
2509                  JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
2510                  uintN flags, intN tinyid)
2511 {
2512     JSAtom *atom;
2513 
2514     atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
2515     if (!atom)
2516         return JS_FALSE;
2517     if (flags != 0 && OBJ_IS_NATIVE(obj)) {
2518         return js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value,
2519                                        getter, setter, attrs, flags, tinyid,
2520                                        NULL);
2521     }
2522     return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), value,
2523                                getter, setter, attrs, NULL);
2524 }
2525 
2526 JS_PUBLIC_API(JSObject *)
JS_DefineObject(JSContext * cx,JSObject * obj,const char * name,JSClass * clasp,JSObject * proto,uintN attrs)2527 JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *clasp,
2528                 JSObject *proto, uintN attrs)
2529 {
2530     JSObject *nobj;
2531 
2532     CHECK_REQUEST(cx);
2533     if (!clasp)
2534         clasp = &js_ObjectClass;    /* default class is Object */
2535     nobj = js_NewObject(cx, clasp, proto, obj);
2536     if (!nobj)
2537         return NULL;
2538     if (!DefineProperty(cx, obj, name, OBJECT_TO_JSVAL(nobj), NULL, NULL, attrs,
2539                         0, 0)) {
2540         cx->weakRoots.newborn[GCX_OBJECT] = NULL;
2541         return NULL;
2542     }
2543     return nobj;
2544 }
2545 
2546 JS_PUBLIC_API(JSBool)
JS_DefineConstDoubles(JSContext * cx,JSObject * obj,JSConstDoubleSpec * cds)2547 JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds)
2548 {
2549     JSBool ok;
2550     jsval value;
2551     uintN flags;
2552 
2553     CHECK_REQUEST(cx);
2554     for (ok = JS_TRUE; cds->name; cds++) {
2555         ok = js_NewNumberValue(cx, cds->dval, &value);
2556         if (!ok)
2557             break;
2558         flags = cds->flags;
2559         if (!flags)
2560             flags = JSPROP_READONLY | JSPROP_PERMANENT;
2561         ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, flags, 0, 0);
2562         if (!ok)
2563             break;
2564     }
2565     return ok;
2566 }
2567 
2568 JS_PUBLIC_API(JSBool)
JS_DefineProperties(JSContext * cx,JSObject * obj,JSPropertySpec * ps)2569 JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps)
2570 {
2571     JSBool ok;
2572 
2573     CHECK_REQUEST(cx);
2574     for (ok = JS_TRUE; ps->name; ps++) {
2575         ok = DefineProperty(cx, obj, ps->name, JSVAL_VOID,
2576                             ps->getter, ps->setter, ps->flags,
2577                             SPROP_HAS_SHORTID, ps->tinyid);
2578         if (!ok)
2579             break;
2580     }
2581     return ok;
2582 }
2583 
2584 JS_PUBLIC_API(JSBool)
JS_DefineProperty(JSContext * cx,JSObject * obj,const char * name,jsval value,JSPropertyOp getter,JSPropertyOp setter,uintN attrs)2585 JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
2586                   JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
2587 {
2588     CHECK_REQUEST(cx);
2589     return DefineProperty(cx, obj, name, value, getter, setter, attrs, 0, 0);
2590 }
2591 
2592 JS_PUBLIC_API(JSBool)
JS_DefinePropertyWithTinyId(JSContext * cx,JSObject * obj,const char * name,int8 tinyid,jsval value,JSPropertyOp getter,JSPropertyOp setter,uintN attrs)2593 JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name,
2594                             int8 tinyid, jsval value,
2595                             JSPropertyOp getter, JSPropertyOp setter,
2596                             uintN attrs)
2597 {
2598     CHECK_REQUEST(cx);
2599     return DefineProperty(cx, obj, name, value, getter, setter, attrs,
2600                           SPROP_HAS_SHORTID, tinyid);
2601 }
2602 
2603 static JSBool
LookupProperty(JSContext * cx,JSObject * obj,const char * name,JSObject ** objp,JSProperty ** propp)2604 LookupProperty(JSContext *cx, JSObject *obj, const char *name, JSObject **objp,
2605                JSProperty **propp)
2606 {
2607     JSAtom *atom;
2608 
2609     atom = js_Atomize(cx, name, strlen(name), 0);
2610     if (!atom)
2611         return JS_FALSE;
2612     return OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), objp, propp);
2613 }
2614 
2615 static JSBool
LookupUCProperty(JSContext * cx,JSObject * obj,const jschar * name,size_t namelen,JSObject ** objp,JSProperty ** propp)2616 LookupUCProperty(JSContext *cx, JSObject *obj,
2617                  const jschar *name, size_t namelen,
2618                  JSObject **objp, JSProperty **propp)
2619 {
2620     JSAtom *atom;
2621 
2622     atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
2623     if (!atom)
2624         return JS_FALSE;
2625     return OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), objp, propp);
2626 }
2627 
2628 JS_PUBLIC_API(JSBool)
JS_AliasProperty(JSContext * cx,JSObject * obj,const char * name,const char * alias)2629 JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name,
2630                  const char *alias)
2631 {
2632     JSObject *obj2;
2633     JSProperty *prop;
2634     JSAtom *atom;
2635     JSBool ok;
2636     JSScopeProperty *sprop;
2637 
2638     CHECK_REQUEST(cx);
2639     if (!LookupProperty(cx, obj, name, &obj2, &prop))
2640         return JS_FALSE;
2641     if (!prop) {
2642         js_ReportIsNotDefined(cx, name);
2643         return JS_FALSE;
2644     }
2645     if (obj2 != obj || !OBJ_IS_NATIVE(obj)) {
2646         OBJ_DROP_PROPERTY(cx, obj2, prop);
2647         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
2648                              alias, name, OBJ_GET_CLASS(cx, obj2)->name);
2649         return JS_FALSE;
2650     }
2651     atom = js_Atomize(cx, alias, strlen(alias), 0);
2652     if (!atom) {
2653         ok = JS_FALSE;
2654     } else {
2655         sprop = (JSScopeProperty *)prop;
2656         ok = (js_AddNativeProperty(cx, obj, ATOM_TO_JSID(atom),
2657                                    sprop->getter, sprop->setter, sprop->slot,
2658                                    sprop->attrs, sprop->flags | SPROP_IS_ALIAS,
2659                                    sprop->shortid)
2660               != NULL);
2661     }
2662     OBJ_DROP_PROPERTY(cx, obj, prop);
2663     return ok;
2664 }
2665 
2666 static jsval
LookupResult(JSContext * cx,JSObject * obj,JSObject * obj2,JSProperty * prop)2667 LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, JSProperty *prop)
2668 {
2669     JSScopeProperty *sprop;
2670     jsval rval;
2671 
2672     if (!prop) {
2673         /* XXX bad API: no way to tell "not defined" from "void value" */
2674         return JSVAL_VOID;
2675     }
2676     if (OBJ_IS_NATIVE(obj2)) {
2677         /* Peek at the native property's slot value, without doing a Get. */
2678         sprop = (JSScopeProperty *)prop;
2679         rval = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj2))
2680                ? LOCKED_OBJ_GET_SLOT(obj2, sprop->slot)
2681                : JSVAL_TRUE;
2682     } else {
2683         /* XXX bad API: no way to return "defined but value unknown" */
2684         rval = JSVAL_TRUE;
2685     }
2686     OBJ_DROP_PROPERTY(cx, obj2, prop);
2687     return rval;
2688 }
2689 
2690 static JSBool
GetPropertyAttributes(JSContext * cx,JSObject * obj,JSAtom * atom,uintN * attrsp,JSBool * foundp,JSPropertyOp * getterp,JSPropertyOp * setterp)2691 GetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom,
2692                       uintN *attrsp, JSBool *foundp,
2693                       JSPropertyOp *getterp, JSPropertyOp *setterp)
2694 {
2695     JSObject *obj2;
2696     JSProperty *prop;
2697     JSBool ok;
2698 
2699     if (!atom)
2700         return JS_FALSE;
2701     if (!OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &obj2, &prop))
2702         return JS_FALSE;
2703 
2704     if (!prop || obj != obj2) {
2705         *attrsp = 0;
2706         *foundp = JS_FALSE;
2707         if (getterp)
2708             *getterp = NULL;
2709         if (setterp)
2710             *setterp = NULL;
2711         if (prop)
2712             OBJ_DROP_PROPERTY(cx, obj2, prop);
2713         return JS_TRUE;
2714     }
2715 
2716     *foundp = JS_TRUE;
2717     ok = OBJ_GET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, attrsp);
2718     if (ok && OBJ_IS_NATIVE(obj)) {
2719         JSScopeProperty *sprop = (JSScopeProperty *) prop;
2720 
2721         if (getterp)
2722             *getterp = sprop->getter;
2723         if (setterp)
2724             *setterp = sprop->setter;
2725     }
2726     OBJ_DROP_PROPERTY(cx, obj, prop);
2727     return ok;
2728 }
2729 
2730 static JSBool
SetPropertyAttributes(JSContext * cx,JSObject * obj,JSAtom * atom,uintN attrs,JSBool * foundp)2731 SetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom,
2732                       uintN attrs, JSBool *foundp)
2733 {
2734     JSObject *obj2;
2735     JSProperty *prop;
2736     JSBool ok;
2737 
2738     if (!atom)
2739         return JS_FALSE;
2740     if (!OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &obj2, &prop))
2741         return JS_FALSE;
2742     if (!prop || obj != obj2) {
2743         *foundp = JS_FALSE;
2744         if (prop)
2745             OBJ_DROP_PROPERTY(cx, obj2, prop);
2746         return JS_TRUE;
2747     }
2748 
2749     *foundp = JS_TRUE;
2750     ok = OBJ_SET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, &attrs);
2751     OBJ_DROP_PROPERTY(cx, obj, prop);
2752     return ok;
2753 }
2754 
2755 JS_PUBLIC_API(JSBool)
JS_GetPropertyAttributes(JSContext * cx,JSObject * obj,const char * name,uintN * attrsp,JSBool * foundp)2756 JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
2757                          uintN *attrsp, JSBool *foundp)
2758 {
2759     CHECK_REQUEST(cx);
2760     return GetPropertyAttributes(cx, obj,
2761                                  js_Atomize(cx, name, strlen(name), 0),
2762                                  attrsp, foundp, NULL, NULL);
2763 }
2764 
2765 JS_PUBLIC_API(JSBool)
JS_GetPropertyAttrsGetterAndSetter(JSContext * cx,JSObject * obj,const char * name,uintN * attrsp,JSBool * foundp,JSPropertyOp * getterp,JSPropertyOp * setterp)2766 JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
2767                                    const char *name,
2768                                    uintN *attrsp, JSBool *foundp,
2769                                    JSPropertyOp *getterp,
2770                                    JSPropertyOp *setterp)
2771 {
2772     CHECK_REQUEST(cx);
2773     return GetPropertyAttributes(cx, obj,
2774                                  js_Atomize(cx, name, strlen(name), 0),
2775                                  attrsp, foundp, getterp, setterp);
2776 }
2777 
2778 JS_PUBLIC_API(JSBool)
JS_SetPropertyAttributes(JSContext * cx,JSObject * obj,const char * name,uintN attrs,JSBool * foundp)2779 JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
2780                          uintN attrs, JSBool *foundp)
2781 {
2782     CHECK_REQUEST(cx);
2783     return SetPropertyAttributes(cx, obj,
2784                                  js_Atomize(cx, name, strlen(name), 0),
2785                                  attrs, foundp);
2786 }
2787 
2788 JS_PUBLIC_API(JSBool)
JS_HasProperty(JSContext * cx,JSObject * obj,const char * name,JSBool * foundp)2789 JS_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
2790 {
2791     JSBool ok;
2792     JSObject *obj2;
2793     JSProperty *prop;
2794 
2795     CHECK_REQUEST(cx);
2796     ok = LookupProperty(cx, obj, name, &obj2, &prop);
2797     if (ok) {
2798         *foundp = (prop != NULL);
2799         if (prop)
2800             OBJ_DROP_PROPERTY(cx, obj2, prop);
2801     }
2802     return ok;
2803 }
2804 
2805 JS_PUBLIC_API(JSBool)
JS_LookupProperty(JSContext * cx,JSObject * obj,const char * name,jsval * vp)2806 JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
2807 {
2808     JSBool ok;
2809     JSObject *obj2;
2810     JSProperty *prop;
2811 
2812     CHECK_REQUEST(cx);
2813     ok = LookupProperty(cx, obj, name, &obj2, &prop);
2814     if (ok)
2815         *vp = LookupResult(cx, obj, obj2, prop);
2816     return ok;
2817 }
2818 
2819 JS_PUBLIC_API(JSBool)
JS_LookupPropertyWithFlags(JSContext * cx,JSObject * obj,const char * name,uintN flags,jsval * vp)2820 JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name,
2821                            uintN flags, jsval *vp)
2822 {
2823     JSAtom *atom;
2824     JSBool ok;
2825     JSObject *obj2;
2826     JSProperty *prop;
2827 
2828     CHECK_REQUEST(cx);
2829     atom = js_Atomize(cx, name, strlen(name), 0);
2830     if (!atom)
2831         return JS_FALSE;
2832     ok = OBJ_IS_NATIVE(obj)
2833          ? js_LookupPropertyWithFlags(cx, obj, ATOM_TO_JSID(atom), flags,
2834                                       &obj2, &prop)
2835          : OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &obj2, &prop);
2836     if (ok)
2837         *vp = LookupResult(cx, obj, obj2, prop);
2838     return ok;
2839 }
2840 
2841 JS_PUBLIC_API(JSBool)
JS_GetProperty(JSContext * cx,JSObject * obj,const char * name,jsval * vp)2842 JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
2843 {
2844     JSAtom *atom;
2845 
2846     CHECK_REQUEST(cx);
2847     atom = js_Atomize(cx, name, strlen(name), 0);
2848     if (!atom)
2849         return JS_FALSE;
2850     return OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
2851 }
2852 
2853 JS_PUBLIC_API(JSBool)
JS_GetMethodById(JSContext * cx,JSObject * obj,jsid id,JSObject ** objp,jsval * vp)2854 JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
2855                  jsval *vp)
2856 {
2857     CHECK_REQUEST(cx);
2858 
2859 #if JS_HAS_XML_SUPPORT
2860     if (OBJECT_IS_XML(cx, obj)) {
2861         JSXMLObjectOps *ops;
2862 
2863         ops = (JSXMLObjectOps *) obj->map->ops;
2864         obj = ops->getMethod(cx, obj, id, vp);
2865         if (!obj)
2866             return JS_FALSE;
2867     } else
2868 #endif
2869     {
2870         if (!OBJ_GET_PROPERTY(cx, obj, id, vp))
2871             return JS_FALSE;
2872     }
2873 
2874     *objp = obj;
2875     return JS_TRUE;
2876 }
2877 
2878 JS_PUBLIC_API(JSBool)
JS_GetMethod(JSContext * cx,JSObject * obj,const char * name,JSObject ** objp,jsval * vp)2879 JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp,
2880              jsval *vp)
2881 {
2882     JSAtom *atom;
2883 
2884     atom = js_Atomize(cx, name, strlen(name), 0);
2885     if (!atom)
2886         return JS_FALSE;
2887     return JS_GetMethodById(cx, obj, ATOM_TO_JSID(atom), objp, vp);
2888 }
2889 
2890 JS_PUBLIC_API(JSBool)
JS_SetProperty(JSContext * cx,JSObject * obj,const char * name,jsval * vp)2891 JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
2892 {
2893     JSAtom *atom;
2894 
2895     CHECK_REQUEST(cx);
2896     atom = js_Atomize(cx, name, strlen(name), 0);
2897     if (!atom)
2898         return JS_FALSE;
2899     return OBJ_SET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
2900 }
2901 
2902 JS_PUBLIC_API(JSBool)
JS_DeleteProperty(JSContext * cx,JSObject * obj,const char * name)2903 JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name)
2904 {
2905     jsval junk;
2906 
2907     CHECK_REQUEST(cx);
2908     return JS_DeleteProperty2(cx, obj, name, &junk);
2909 }
2910 
2911 JS_PUBLIC_API(JSBool)
JS_DeleteProperty2(JSContext * cx,JSObject * obj,const char * name,jsval * rval)2912 JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name,
2913                    jsval *rval)
2914 {
2915     JSAtom *atom;
2916 
2917     CHECK_REQUEST(cx);
2918     atom = js_Atomize(cx, name, strlen(name), 0);
2919     if (!atom)
2920         return JS_FALSE;
2921     return OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval);
2922 }
2923 
2924 JS_PUBLIC_API(JSBool)
JS_DefineUCProperty(JSContext * cx,JSObject * obj,const jschar * name,size_t namelen,jsval value,JSPropertyOp getter,JSPropertyOp setter,uintN attrs)2925 JS_DefineUCProperty(JSContext *cx, JSObject *obj,
2926                     const jschar *name, size_t namelen, jsval value,
2927                     JSPropertyOp getter, JSPropertyOp setter,
2928                     uintN attrs)
2929 {
2930     CHECK_REQUEST(cx);
2931     return DefineUCProperty(cx, obj, name, namelen, value, getter, setter,
2932                             attrs, 0, 0);
2933 }
2934 
2935 JS_PUBLIC_API(JSBool)
JS_GetUCPropertyAttributes(JSContext * cx,JSObject * obj,const jschar * name,size_t namelen,uintN * attrsp,JSBool * foundp)2936 JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj,
2937                            const jschar *name, size_t namelen,
2938                            uintN *attrsp, JSBool *foundp)
2939 {
2940     CHECK_REQUEST(cx);
2941     return GetPropertyAttributes(cx, obj,
2942                     js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
2943                     attrsp, foundp, NULL, NULL);
2944 }
2945 
2946 JS_PUBLIC_API(JSBool)
JS_GetUCPropertyAttrsGetterAndSetter(JSContext * cx,JSObject * obj,const jschar * name,size_t namelen,uintN * attrsp,JSBool * foundp,JSPropertyOp * getterp,JSPropertyOp * setterp)2947 JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
2948                                      const jschar *name, size_t namelen,
2949                                      uintN *attrsp, JSBool *foundp,
2950                                      JSPropertyOp *getterp,
2951                                      JSPropertyOp *setterp)
2952 {
2953     CHECK_REQUEST(cx);
2954     return GetPropertyAttributes(cx, obj,
2955                     js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
2956                     attrsp, foundp, getterp, setterp);
2957 }
2958 
2959 JS_PUBLIC_API(JSBool)
JS_SetUCPropertyAttributes(JSContext * cx,JSObject * obj,const jschar * name,size_t namelen,uintN attrs,JSBool * foundp)2960 JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj,
2961                            const jschar *name, size_t namelen,
2962                            uintN attrs, JSBool *foundp)
2963 {
2964     CHECK_REQUEST(cx);
2965     return SetPropertyAttributes(cx, obj,
2966                     js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
2967                     attrs, foundp);
2968 }
2969 
2970 JS_PUBLIC_API(JSBool)
JS_DefineUCPropertyWithTinyId(JSContext * cx,JSObject * obj,const jschar * name,size_t namelen,int8 tinyid,jsval value,JSPropertyOp getter,JSPropertyOp setter,uintN attrs)2971 JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj,
2972                               const jschar *name, size_t namelen,
2973                               int8 tinyid, jsval value,
2974                               JSPropertyOp getter, JSPropertyOp setter,
2975                               uintN attrs)
2976 {
2977     CHECK_REQUEST(cx);
2978     return DefineUCProperty(cx, obj, name, namelen, value, getter, setter,
2979                             attrs, SPROP_HAS_SHORTID, tinyid);
2980 }
2981 
2982 JS_PUBLIC_API(JSBool)
JS_HasUCProperty(JSContext * cx,JSObject * obj,const jschar * name,size_t namelen,JSBool * vp)2983 JS_HasUCProperty(JSContext *cx, JSObject *obj,
2984                  const jschar *name, size_t namelen,
2985                  JSBool *vp)
2986 {
2987     JSBool ok;
2988     JSObject *obj2;
2989     JSProperty *prop;
2990 
2991     CHECK_REQUEST(cx);
2992     ok = LookupUCProperty(cx, obj, name, namelen, &obj2, &prop);
2993     if (ok) {
2994         *vp = (prop != NULL);
2995         if (prop)
2996             OBJ_DROP_PROPERTY(cx, obj2, prop);
2997     }
2998     return ok;
2999 }
3000 
3001 JS_PUBLIC_API(JSBool)
JS_LookupUCProperty(JSContext * cx,JSObject * obj,const jschar * name,size_t namelen,jsval * vp)3002 JS_LookupUCProperty(JSContext *cx, JSObject *obj,
3003                     const jschar *name, size_t namelen,
3004                     jsval *vp)
3005 {
3006     JSBool ok;
3007     JSObject *obj2;
3008     JSProperty *prop;
3009 
3010     CHECK_REQUEST(cx);
3011     ok = LookupUCProperty(cx, obj, name, namelen, &obj2, &prop);
3012     if (ok)
3013         *vp = LookupResult(cx, obj, obj2, prop);
3014     return ok;
3015 }
3016 
3017 JS_PUBLIC_API(JSBool)
JS_GetUCProperty(JSContext * cx,JSObject * obj,const jschar * name,size_t namelen,jsval * vp)3018 JS_GetUCProperty(JSContext *cx, JSObject *obj,
3019                  const jschar *name, size_t namelen,
3020                  jsval *vp)
3021 {
3022     JSAtom *atom;
3023 
3024     CHECK_REQUEST(cx);
3025     atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3026     if (!atom)
3027         return JS_FALSE;
3028     return OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
3029 }
3030 
3031 JS_PUBLIC_API(JSBool)
JS_SetUCProperty(JSContext * cx,JSObject * obj,const jschar * name,size_t namelen,jsval * vp)3032 JS_SetUCProperty(JSContext *cx, JSObject *obj,
3033                  const jschar *name, size_t namelen,
3034                  jsval *vp)
3035 {
3036     JSAtom *atom;
3037 
3038     CHECK_REQUEST(cx);
3039     atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3040     if (!atom)
3041         return JS_FALSE;
3042     return OBJ_SET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
3043 }
3044 
3045 JS_PUBLIC_API(JSBool)
JS_DeleteUCProperty2(JSContext * cx,JSObject * obj,const jschar * name,size_t namelen,jsval * rval)3046 JS_DeleteUCProperty2(JSContext *cx, JSObject *obj,
3047                      const jschar *name, size_t namelen,
3048                      jsval *rval)
3049 {
3050     JSAtom *atom;
3051 
3052     CHECK_REQUEST(cx);
3053     atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3054     if (!atom)
3055         return JS_FALSE;
3056     return OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval);
3057 }
3058 
3059 JS_PUBLIC_API(JSObject *)
JS_NewArrayObject(JSContext * cx,jsint length,jsval * vector)3060 JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
3061 {
3062     CHECK_REQUEST(cx);
3063     /* NB: jsuint cast does ToUint32. */
3064     return js_NewArrayObject(cx, (jsuint)length, vector);
3065 }
3066 
3067 JS_PUBLIC_API(JSBool)
JS_IsArrayObject(JSContext * cx,JSObject * obj)3068 JS_IsArrayObject(JSContext *cx, JSObject *obj)
3069 {
3070     return OBJ_GET_CLASS(cx, obj) == &js_ArrayClass;
3071 }
3072 
3073 JS_PUBLIC_API(JSBool)
JS_GetArrayLength(JSContext * cx,JSObject * obj,jsuint * lengthp)3074 JS_GetArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
3075 {
3076     CHECK_REQUEST(cx);
3077     return js_GetLengthProperty(cx, obj, lengthp);
3078 }
3079 
3080 JS_PUBLIC_API(JSBool)
JS_SetArrayLength(JSContext * cx,JSObject * obj,jsuint length)3081 JS_SetArrayLength(JSContext *cx, JSObject *obj, jsuint length)
3082 {
3083     CHECK_REQUEST(cx);
3084     return js_SetLengthProperty(cx, obj, length);
3085 }
3086 
3087 JS_PUBLIC_API(JSBool)
JS_HasArrayLength(JSContext * cx,JSObject * obj,jsuint * lengthp)3088 JS_HasArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
3089 {
3090     CHECK_REQUEST(cx);
3091     return js_HasLengthProperty(cx, obj, lengthp);
3092 }
3093 
3094 JS_PUBLIC_API(JSBool)
JS_DefineElement(JSContext * cx,JSObject * obj,jsint index,jsval value,JSPropertyOp getter,JSPropertyOp setter,uintN attrs)3095 JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value,
3096                  JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3097 {
3098     CHECK_REQUEST(cx);
3099     return OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSID(index), value,
3100                                getter, setter, attrs, NULL);
3101 }
3102 
3103 JS_PUBLIC_API(JSBool)
JS_AliasElement(JSContext * cx,JSObject * obj,const char * name,jsint alias)3104 JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
3105 {
3106     JSObject *obj2;
3107     JSProperty *prop;
3108     JSScopeProperty *sprop;
3109     JSBool ok;
3110 
3111     CHECK_REQUEST(cx);
3112     if (!LookupProperty(cx, obj, name, &obj2, &prop))
3113         return JS_FALSE;
3114     if (!prop) {
3115         js_ReportIsNotDefined(cx, name);
3116         return JS_FALSE;
3117     }
3118     if (obj2 != obj || !OBJ_IS_NATIVE(obj)) {
3119         char numBuf[12];
3120         OBJ_DROP_PROPERTY(cx, obj2, prop);
3121         JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)alias);
3122         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
3123                              numBuf, name, OBJ_GET_CLASS(cx, obj2)->name);
3124         return JS_FALSE;
3125     }
3126     sprop = (JSScopeProperty *)prop;
3127     ok = (js_AddNativeProperty(cx, obj, INT_TO_JSID(alias),
3128                                sprop->getter, sprop->setter, sprop->slot,
3129                                sprop->attrs, sprop->flags | SPROP_IS_ALIAS,
3130                                sprop->shortid)
3131           != NULL);
3132     OBJ_DROP_PROPERTY(cx, obj, prop);
3133     return ok;
3134 }
3135 
3136 JS_PUBLIC_API(JSBool)
JS_HasElement(JSContext * cx,JSObject * obj,jsint index,JSBool * foundp)3137 JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
3138 {
3139     JSBool ok;
3140     JSObject *obj2;
3141     JSProperty *prop;
3142 
3143     CHECK_REQUEST(cx);
3144     ok = OBJ_LOOKUP_PROPERTY(cx, obj, INT_TO_JSID(index), &obj2, &prop);
3145     if (ok) {
3146         *foundp = (prop != NULL);
3147         if (prop)
3148             OBJ_DROP_PROPERTY(cx, obj2, prop);
3149     }
3150     return ok;
3151 }
3152 
3153 JS_PUBLIC_API(JSBool)
JS_LookupElement(JSContext * cx,JSObject * obj,jsint index,jsval * vp)3154 JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3155 {
3156     JSBool ok;
3157     JSObject *obj2;
3158     JSProperty *prop;
3159 
3160     CHECK_REQUEST(cx);
3161     ok = OBJ_LOOKUP_PROPERTY(cx, obj, INT_TO_JSID(index), &obj2, &prop);
3162     if (ok)
3163         *vp = LookupResult(cx, obj, obj2, prop);
3164     return ok;
3165 }
3166 
3167 JS_PUBLIC_API(JSBool)
JS_GetElement(JSContext * cx,JSObject * obj,jsint index,jsval * vp)3168 JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3169 {
3170     CHECK_REQUEST(cx);
3171     return OBJ_GET_PROPERTY(cx, obj, INT_TO_JSID(index), vp);
3172 }
3173 
3174 JS_PUBLIC_API(JSBool)
JS_SetElement(JSContext * cx,JSObject * obj,jsint index,jsval * vp)3175 JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3176 {
3177     CHECK_REQUEST(cx);
3178     return OBJ_SET_PROPERTY(cx, obj, INT_TO_JSID(index), vp);
3179 }
3180 
3181 JS_PUBLIC_API(JSBool)
JS_DeleteElement(JSContext * cx,JSObject * obj,jsint index)3182 JS_DeleteElement(JSContext *cx, JSObject *obj, jsint index)
3183 {
3184     jsval junk;
3185 
3186     CHECK_REQUEST(cx);
3187     return JS_DeleteElement2(cx, obj, index, &junk);
3188 }
3189 
3190 JS_PUBLIC_API(JSBool)
JS_DeleteElement2(JSContext * cx,JSObject * obj,jsint index,jsval * rval)3191 JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval)
3192 {
3193     CHECK_REQUEST(cx);
3194     return OBJ_DELETE_PROPERTY(cx, obj, INT_TO_JSID(index), rval);
3195 }
3196 
3197 JS_PUBLIC_API(void)
JS_ClearScope(JSContext * cx,JSObject * obj)3198 JS_ClearScope(JSContext *cx, JSObject *obj)
3199 {
3200     CHECK_REQUEST(cx);
3201 
3202     if (obj->map->ops->clear)
3203         obj->map->ops->clear(cx, obj);
3204 
3205     /* Clear cached class objects on the global object. */
3206     if (JS_GET_CLASS(cx, obj)->flags & JSCLASS_IS_GLOBAL) {
3207         JSProtoKey key;
3208 
3209         for (key = JSProto_Null; key < JSProto_LIMIT; key++)
3210             JS_SetReservedSlot(cx, obj, key, JSVAL_VOID);
3211     }
3212 }
3213 
3214 JS_PUBLIC_API(JSIdArray *)
JS_Enumerate(JSContext * cx,JSObject * obj)3215 JS_Enumerate(JSContext *cx, JSObject *obj)
3216 {
3217     jsint i, n;
3218     jsval iter_state, num_properties;
3219     jsid id;
3220     JSIdArray *ida;
3221     jsval *vector;
3222 
3223     CHECK_REQUEST(cx);
3224 
3225     ida = NULL;
3226     iter_state = JSVAL_NULL;
3227 
3228     /* Get the number of properties to enumerate. */
3229     if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, &num_properties))
3230         goto error;
3231     if (!JSVAL_IS_INT(num_properties)) {
3232         JS_ASSERT(0);
3233         goto error;
3234     }
3235 
3236     /* Grow as needed if we don't know the exact amount ahead of time. */
3237     n = JSVAL_TO_INT(num_properties);
3238     if (n <= 0)
3239         n = 8;
3240 
3241     /* Create an array of jsids large enough to hold all the properties */
3242     ida = js_NewIdArray(cx, n);
3243     if (!ida)
3244         goto error;
3245 
3246     i = 0;
3247     vector = &ida->vector[0];
3248     for (;;) {
3249         if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &iter_state, &id))
3250             goto error;
3251 
3252         /* No more jsid's to enumerate ? */
3253         if (iter_state == JSVAL_NULL)
3254             break;
3255 
3256         if (i == ida->length) {
3257             ida = js_SetIdArrayLength(cx, ida, ida->length * 2);
3258             if (!ida)
3259                 goto error;
3260             vector = &ida->vector[0];
3261         }
3262         vector[i++] = id;
3263     }
3264     return js_SetIdArrayLength(cx, ida, i);
3265 
3266 error:
3267     if (iter_state != JSVAL_NULL)
3268         OBJ_ENUMERATE(cx, obj, JSENUMERATE_DESTROY, &iter_state, 0);
3269     if (ida)
3270         JS_DestroyIdArray(cx, ida);
3271     return NULL;
3272 }
3273 
3274 /*
3275  * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
3276  *     prop_iterator_class somehow...
3277  * + preserve the OBJ_ENUMERATE API while optimizing the native object case
3278  * + native case here uses a JSScopeProperty *, but that iterates in reverse!
3279  * + so we make non-native match, by reverse-iterating after JS_Enumerating
3280  */
3281 #define JSSLOT_ITER_INDEX       (JSSLOT_PRIVATE + 1)
3282 
3283 #if JSSLOT_ITER_INDEX >= JS_INITIAL_NSLOTS
3284 # error "JSSLOT_ITER_INDEX botch!"
3285 #endif
3286 
3287 static void
prop_iter_finalize(JSContext * cx,JSObject * obj)3288 prop_iter_finalize(JSContext *cx, JSObject *obj)
3289 {
3290     jsval v;
3291     jsint i;
3292     JSIdArray *ida;
3293 
3294     v = GC_AWARE_GET_SLOT(cx, obj, JSSLOT_ITER_INDEX);
3295     if (JSVAL_IS_VOID(v))
3296         return;
3297 
3298     i = JSVAL_TO_INT(v);
3299     if (i >= 0) {
3300         /* Non-native case: destroy the ida enumerated when obj was created. */
3301         ida = (JSIdArray *) JS_GetPrivate(cx, obj);
3302         if (ida)
3303             JS_DestroyIdArray(cx, ida);
3304     }
3305 }
3306 
3307 static uint32
prop_iter_mark(JSContext * cx,JSObject * obj,void * arg)3308 prop_iter_mark(JSContext *cx, JSObject *obj, void *arg)
3309 {
3310     jsval v;
3311     jsint i, n;
3312     JSScopeProperty *sprop;
3313     JSIdArray *ida;
3314     jsid id;
3315 
3316     v = GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
3317     JS_ASSERT(!JSVAL_IS_VOID(v));
3318 
3319     i = JSVAL_TO_INT(OBJ_GET_SLOT(cx, obj, JSSLOT_ITER_INDEX));
3320     if (i < 0) {
3321         /* Native case: just mark the next property to visit. */
3322         sprop = (JSScopeProperty *) JSVAL_TO_PRIVATE(v);
3323         if (sprop)
3324             MARK_SCOPE_PROPERTY(cx, sprop);
3325     } else {
3326         /* Non-native case: mark each id in the JSIdArray private. */
3327         ida = (JSIdArray *) JSVAL_TO_PRIVATE(v);
3328         for (i = 0, n = ida->length; i < n; i++) {
3329             id = ida->vector[i];
3330             MARK_ID(cx, id);
3331         }
3332     }
3333     return 0;
3334 }
3335 
3336 static JSClass prop_iter_class = {
3337     "PropertyIterator",
3338     JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1),
3339     JS_PropertyStub,  JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
3340     JS_EnumerateStub, JS_ResolveStub,  JS_ConvertStub,  prop_iter_finalize,
3341     NULL,             NULL,            NULL,            NULL,
3342     NULL,             NULL,            prop_iter_mark,  NULL
3343 };
3344 
3345 JS_PUBLIC_API(JSObject *)
JS_NewPropertyIterator(JSContext * cx,JSObject * obj)3346 JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
3347 {
3348     JSObject *iterobj;
3349     JSScope *scope;
3350     void *pdata;
3351     jsint index;
3352     JSIdArray *ida;
3353 
3354     CHECK_REQUEST(cx);
3355     iterobj = js_NewObject(cx, &prop_iter_class, NULL, obj);
3356     if (!iterobj)
3357         return NULL;
3358 
3359     if (OBJ_IS_NATIVE(obj)) {
3360         /* Native case: start with the last property in obj's own scope. */
3361         scope = OBJ_SCOPE(obj);
3362         pdata = (scope->object == obj) ? scope->lastProp : NULL;
3363         index = -1;
3364     } else {
3365         JSTempValueRooter tvr;
3366 
3367         /*
3368          * Non-native case: enumerate a JSIdArray and keep it via private.
3369          *
3370          * Note: we have to make sure that we root obj around the call to
3371          * JS_Enumerate to protect against multiple allocations under it.
3372          */
3373         JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(iterobj), &tvr);
3374         ida = JS_Enumerate(cx, obj);
3375         JS_POP_TEMP_ROOT(cx, &tvr);
3376         if (!ida)
3377             goto bad;
3378         pdata = ida;
3379         index = ida->length;
3380     }
3381 
3382     /* iterobj can not escape to other threads here. */
3383     iterobj->slots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(pdata);
3384     iterobj->slots[JSSLOT_ITER_INDEX] = INT_TO_JSVAL(index);
3385     return iterobj;
3386 
3387   bad:
3388     cx->weakRoots.newborn[GCX_OBJECT] = NULL;
3389     return NULL;
3390 }
3391 
3392 JS_PUBLIC_API(JSBool)
JS_NextProperty(JSContext * cx,JSObject * iterobj,jsid * idp)3393 JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
3394 {
3395     jsint i;
3396     JSObject *obj;
3397     JSScope *scope;
3398     JSScopeProperty *sprop;
3399     JSIdArray *ida;
3400 
3401     CHECK_REQUEST(cx);
3402     i = JSVAL_TO_INT(OBJ_GET_SLOT(cx, iterobj, JSSLOT_ITER_INDEX));
3403     if (i < 0) {
3404         /* Native case: private data is a property tree node pointer. */
3405         obj = OBJ_GET_PARENT(cx, iterobj);
3406         JS_ASSERT(OBJ_IS_NATIVE(obj));
3407         scope = OBJ_SCOPE(obj);
3408         JS_ASSERT(scope->object == obj);
3409         sprop = (JSScopeProperty *) JS_GetPrivate(cx, iterobj);
3410 
3411         /*
3412          * If the next property mapped by scope in the property tree ancestor
3413          * line is not enumerable, or it's an alias, or one or more properties
3414          * were deleted from the "middle" of the scope-mapped ancestor line
3415          * and the next property was among those deleted, skip it and keep on
3416          * trying to find an enumerable property that is still in scope.
3417          */
3418         while (sprop &&
3419                (!(sprop->attrs & JSPROP_ENUMERATE) ||
3420                 (sprop->flags & SPROP_IS_ALIAS) ||
3421                 (SCOPE_HAD_MIDDLE_DELETE(scope) &&
3422                  !SCOPE_HAS_PROPERTY(scope, sprop)))) {
3423             sprop = sprop->parent;
3424         }
3425 
3426         if (!sprop) {
3427             *idp = JSVAL_VOID;
3428         } else {
3429             if (!JS_SetPrivate(cx, iterobj, sprop->parent))
3430                 return JS_FALSE;
3431             *idp = sprop->id;
3432         }
3433     } else {
3434         /* Non-native case: use the ida enumerated when iterobj was created. */
3435         ida = (JSIdArray *) JS_GetPrivate(cx, iterobj);
3436         JS_ASSERT(i <= ida->length);
3437         if (i == 0) {
3438             *idp = JSVAL_VOID;
3439         } else {
3440             *idp = ida->vector[--i];
3441             OBJ_SET_SLOT(cx, iterobj, JSSLOT_ITER_INDEX, INT_TO_JSVAL(i));
3442         }
3443     }
3444     return JS_TRUE;
3445 }
3446 
3447 JS_PUBLIC_API(JSBool)
JS_CheckAccess(JSContext * cx,JSObject * obj,jsid id,JSAccessMode mode,jsval * vp,uintN * attrsp)3448 JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
3449                jsval *vp, uintN *attrsp)
3450 {
3451     CHECK_REQUEST(cx);
3452     return OBJ_CHECK_ACCESS(cx, obj, id, mode, vp, attrsp);
3453 }
3454 
3455 JS_PUBLIC_API(JSCheckAccessOp)
JS_SetCheckObjectAccessCallback(JSRuntime * rt,JSCheckAccessOp acb)3456 JS_SetCheckObjectAccessCallback(JSRuntime *rt, JSCheckAccessOp acb)
3457 {
3458     JSCheckAccessOp oldacb;
3459 
3460     oldacb = rt->checkObjectAccess;
3461     rt->checkObjectAccess = acb;
3462     return oldacb;
3463 }
3464 
3465 static JSBool
ReservedSlotIndexOK(JSContext * cx,JSObject * obj,JSClass * clasp,uint32 index,uint32 limit)3466 ReservedSlotIndexOK(JSContext *cx, JSObject *obj, JSClass *clasp,
3467                     uint32 index, uint32 limit)
3468 {
3469     /* Check the computed, possibly per-instance, upper bound. */
3470     if (clasp->reserveSlots)
3471         JS_LOCK_OBJ_VOID(cx, obj, limit += clasp->reserveSlots(cx, obj));
3472     if (index >= limit) {
3473         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
3474                              JSMSG_RESERVED_SLOT_RANGE);
3475         return JS_FALSE;
3476     }
3477     return JS_TRUE;
3478 }
3479 
3480 JS_PUBLIC_API(JSBool)
JS_GetReservedSlot(JSContext * cx,JSObject * obj,uint32 index,jsval * vp)3481 JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp)
3482 {
3483     JSClass *clasp;
3484     uint32 limit, slot;
3485 
3486     CHECK_REQUEST(cx);
3487     clasp = OBJ_GET_CLASS(cx, obj);
3488     limit = JSCLASS_RESERVED_SLOTS(clasp);
3489     if (index >= limit && !ReservedSlotIndexOK(cx, obj, clasp, index, limit))
3490         return JS_FALSE;
3491     slot = JSSLOT_START(clasp) + index;
3492     *vp = OBJ_GET_REQUIRED_SLOT(cx, obj, slot);
3493     return JS_TRUE;
3494 }
3495 
3496 JS_PUBLIC_API(JSBool)
JS_SetReservedSlot(JSContext * cx,JSObject * obj,uint32 index,jsval v)3497 JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v)
3498 {
3499     JSClass *clasp;
3500     uint32 limit, slot;
3501 
3502     CHECK_REQUEST(cx);
3503     clasp = OBJ_GET_CLASS(cx, obj);
3504     limit = JSCLASS_RESERVED_SLOTS(clasp);
3505     if (index >= limit && !ReservedSlotIndexOK(cx, obj, clasp, index, limit))
3506         return JS_FALSE;
3507     slot = JSSLOT_START(clasp) + index;
3508     return OBJ_SET_REQUIRED_SLOT(cx, obj, slot, v);
3509 }
3510 
3511 #ifdef JS_THREADSAFE
3512 JS_PUBLIC_API(jsrefcount)
JS_HoldPrincipals(JSContext * cx,JSPrincipals * principals)3513 JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals)
3514 {
3515     return JS_ATOMIC_INCREMENT(&principals->refcount);
3516 }
3517 
3518 JS_PUBLIC_API(jsrefcount)
JS_DropPrincipals(JSContext * cx,JSPrincipals * principals)3519 JS_DropPrincipals(JSContext *cx, JSPrincipals *principals)
3520 {
3521     jsrefcount rc = JS_ATOMIC_DECREMENT(&principals->refcount);
3522     if (rc == 0)
3523         principals->destroy(cx, principals);
3524     return rc;
3525 }
3526 #endif
3527 
3528 JS_PUBLIC_API(JSPrincipalsTranscoder)
JS_SetPrincipalsTranscoder(JSRuntime * rt,JSPrincipalsTranscoder px)3529 JS_SetPrincipalsTranscoder(JSRuntime *rt, JSPrincipalsTranscoder px)
3530 {
3531     JSPrincipalsTranscoder oldpx;
3532 
3533     oldpx = rt->principalsTranscoder;
3534     rt->principalsTranscoder = px;
3535     return oldpx;
3536 }
3537 
3538 JS_PUBLIC_API(JSObjectPrincipalsFinder)
JS_SetObjectPrincipalsFinder(JSRuntime * rt,JSObjectPrincipalsFinder fop)3539 JS_SetObjectPrincipalsFinder(JSRuntime *rt, JSObjectPrincipalsFinder fop)
3540 {
3541     JSObjectPrincipalsFinder oldfop;
3542 
3543     oldfop = rt->findObjectPrincipals;
3544     rt->findObjectPrincipals = fop;
3545     return oldfop;
3546 }
3547 
3548 JS_PUBLIC_API(JSFunction *)
JS_NewFunction(JSContext * cx,JSNative native,uintN nargs,uintN flags,JSObject * parent,const char * name)3549 JS_NewFunction(JSContext *cx, JSNative native, uintN nargs, uintN flags,
3550                JSObject *parent, const char *name)
3551 {
3552     JSAtom *atom;
3553 
3554     CHECK_REQUEST(cx);
3555 
3556     if (!name) {
3557         atom = NULL;
3558     } else {
3559         atom = js_Atomize(cx, name, strlen(name), 0);
3560         if (!atom)
3561             return NULL;
3562     }
3563     return js_NewFunction(cx, NULL, native, nargs, flags, parent, atom);
3564 }
3565 
3566 JS_PUBLIC_API(JSObject *)
JS_CloneFunctionObject(JSContext * cx,JSObject * funobj,JSObject * parent)3567 JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
3568 {
3569     CHECK_REQUEST(cx);
3570     if (OBJ_GET_CLASS(cx, funobj) != &js_FunctionClass) {
3571         /* Indicate we cannot clone this object. */
3572         return funobj;
3573     }
3574     return js_CloneFunctionObject(cx, funobj, parent);
3575 }
3576 
3577 JS_PUBLIC_API(JSObject *)
JS_GetFunctionObject(JSFunction * fun)3578 JS_GetFunctionObject(JSFunction *fun)
3579 {
3580     return fun->object;
3581 }
3582 
3583 JS_PUBLIC_API(const char *)
JS_GetFunctionName(JSFunction * fun)3584 JS_GetFunctionName(JSFunction *fun)
3585 {
3586     return fun->atom
3587            ? JS_GetStringBytes(ATOM_TO_STRING(fun->atom))
3588            : js_anonymous_str;
3589 }
3590 
3591 JS_PUBLIC_API(JSString *)
JS_GetFunctionId(JSFunction * fun)3592 JS_GetFunctionId(JSFunction *fun)
3593 {
3594     return fun->atom ? ATOM_TO_STRING(fun->atom) : NULL;
3595 }
3596 
3597 JS_PUBLIC_API(uintN)
JS_GetFunctionFlags(JSFunction * fun)3598 JS_GetFunctionFlags(JSFunction *fun)
3599 {
3600 #ifdef MOZILLA_1_8_BRANCH
3601     uintN flags = fun->flags;
3602 
3603     return JSFUN_DISJOINT_FLAGS(flags) |
3604            (JSFUN_GETTER_TEST(flags) ? JSFUN_GETTER : 0) |
3605            (JSFUN_SETTER_TEST(flags) ? JSFUN_SETTER : 0) |
3606            (JSFUN_BOUND_METHOD_TEST(flags) ? JSFUN_BOUND_METHOD : 0) |
3607            (JSFUN_HEAVYWEIGHT_TEST(flags) ? JSFUN_HEAVYWEIGHT : 0);
3608 #else
3609     return fun->flags;
3610 #endif
3611 }
3612 
3613 JS_PUBLIC_API(uint16)
JS_GetFunctionArity(JSFunction * fun)3614 JS_GetFunctionArity(JSFunction *fun)
3615 {
3616     return fun->nargs;
3617 }
3618 
3619 JS_PUBLIC_API(JSBool)
JS_ObjectIsFunction(JSContext * cx,JSObject * obj)3620 JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
3621 {
3622     return OBJ_GET_CLASS(cx, obj) == &js_FunctionClass;
3623 }
3624 
3625 JS_STATIC_DLL_CALLBACK(JSBool)
js_generic_native_method_dispatcher(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)3626 js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj,
3627                                     uintN argc, jsval *argv, jsval *rval)
3628 {
3629     jsval fsv;
3630     JSFunctionSpec *fs;
3631     JSObject *tmp;
3632 
3633     if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(argv[-2]), 0, &fsv))
3634         return JS_FALSE;
3635     fs = (JSFunctionSpec *) JSVAL_TO_PRIVATE(fsv);
3636 
3637     /*
3638      * We know that argv[0] is valid because JS_DefineFunctions, which is our
3639      * only (indirect) referrer, defined us as requiring at least one argument
3640      * (notice how it passes fs->nargs + 1 as the next-to-last argument to
3641      * JS_DefineFunction).
3642      */
3643     if (JSVAL_IS_PRIMITIVE(argv[0])) {
3644         /*
3645          * Make sure that this is an object or null, as required by the generic
3646          * functions.
3647          */
3648         if (!js_ValueToObject(cx, argv[0], &tmp))
3649             return JS_FALSE;
3650         argv[0] = OBJECT_TO_JSVAL(tmp);
3651     }
3652 
3653     /*
3654      * Copy all actual (argc) and required but missing (fs->nargs + 1 - argc)
3655      * args down over our |this| parameter, argv[-1], which is almost always
3656      * the class constructor object, e.g. Array.  Then call the corresponding
3657      * prototype native method with our first argument passed as |this|.
3658      */
3659     memmove(argv - 1, argv, JS_MAX(fs->nargs + 1U, argc) * sizeof(jsval));
3660 
3661     /*
3662      * Follow Function.prototype.apply and .call by using the global object as
3663      * the 'this' param if no args.
3664      */
3665     JS_ASSERT(cx->fp->argv == argv);
3666     tmp = js_ComputeThis(cx, JSVAL_TO_OBJECT(argv[-1]), argv);
3667     if (!tmp)
3668         return JS_FALSE;
3669     cx->fp->thisp = tmp;
3670 
3671     /*
3672      * Protect against argc - 1 underflowing below. By calling js_ComputeThis,
3673      * we made it as if the static was called with one parameter.
3674      */
3675     if (argc == 0)
3676         argc = 1;
3677 
3678     return fs->call(cx, JSVAL_TO_OBJECT(argv[-1]), argc - 1, argv, rval);
3679 }
3680 
3681 JS_PUBLIC_API(JSBool)
JS_DefineFunctions(JSContext * cx,JSObject * obj,JSFunctionSpec * fs)3682 JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs)
3683 {
3684     uintN flags;
3685     JSObject *ctor;
3686     JSFunction *fun;
3687 
3688     CHECK_REQUEST(cx);
3689     ctor = NULL;
3690     for (; fs->name; fs++) {
3691 
3692         /* High bits of fs->extra are reserved. */
3693         JS_ASSERT((fs->extra & 0xFFFF0000) == 0);
3694         flags = fs->flags;
3695 
3696         /*
3697          * Define a generic arity N+1 static method for the arity N prototype
3698          * method if flags contains JSFUN_GENERIC_NATIVE.
3699          */
3700         if (flags & JSFUN_GENERIC_NATIVE) {
3701             if (!ctor) {
3702                 ctor = JS_GetConstructor(cx, obj);
3703                 if (!ctor)
3704                     return JS_FALSE;
3705             }
3706 
3707             flags &= ~JSFUN_GENERIC_NATIVE;
3708             fun = JS_DefineFunction(cx, ctor, fs->name,
3709                                     js_generic_native_method_dispatcher,
3710                                     fs->nargs + 1, flags);
3711             if (!fun)
3712                 return JS_FALSE;
3713             fun->u.n.extra = (uint16)fs->extra;
3714 
3715             /*
3716              * As jsapi.h notes, fs must point to storage that lives as long
3717              * as fun->object lives.
3718              */
3719             if (!JS_SetReservedSlot(cx, fun->object, 0, PRIVATE_TO_JSVAL(fs)))
3720                 return JS_FALSE;
3721         }
3722 
3723         fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs, flags);
3724         if (!fun)
3725             return JS_FALSE;
3726         fun->u.n.extra = (uint16)fs->extra;
3727     }
3728     return JS_TRUE;
3729 }
3730 
3731 JS_PUBLIC_API(JSFunction *)
JS_DefineFunction(JSContext * cx,JSObject * obj,const char * name,JSNative call,uintN nargs,uintN attrs)3732 JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call,
3733                   uintN nargs, uintN attrs)
3734 {
3735     JSAtom *atom;
3736 
3737     CHECK_REQUEST(cx);
3738     atom = js_Atomize(cx, name, strlen(name), 0);
3739     if (!atom)
3740         return NULL;
3741     return js_DefineFunction(cx, obj, atom, call, nargs, attrs);
3742 }
3743 
3744 JS_PUBLIC_API(JSFunction *)
JS_DefineUCFunction(JSContext * cx,JSObject * obj,const jschar * name,size_t namelen,JSNative call,uintN nargs,uintN attrs)3745 JS_DefineUCFunction(JSContext *cx, JSObject *obj,
3746                     const jschar *name, size_t namelen, JSNative call,
3747                     uintN nargs, uintN attrs)
3748 {
3749     JSAtom *atom;
3750 
3751     atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3752     if (!atom)
3753         return NULL;
3754     return js_DefineFunction(cx, obj, atom, call, nargs, attrs);
3755 }
3756 
3757 static JSScript *
CompileTokenStream(JSContext * cx,JSObject * obj,JSTokenStream * ts,void * tempMark,JSBool * eofp)3758 CompileTokenStream(JSContext *cx, JSObject *obj, JSTokenStream *ts,
3759                    void *tempMark, JSBool *eofp)
3760 {
3761     JSBool eof;
3762     JSArenaPool codePool, notePool;
3763     JSCodeGenerator cg;
3764     JSScript *script;
3765 
3766     CHECK_REQUEST(cx);
3767     eof = JS_FALSE;
3768     JS_InitArenaPool(&codePool, "code", 1024, sizeof(jsbytecode));
3769     JS_InitArenaPool(&notePool, "note", 1024, sizeof(jssrcnote));
3770     if (!js_InitCodeGenerator(cx, &cg, &codePool, &notePool,
3771                               ts->filename, ts->lineno,
3772                               ts->principals)) {
3773         script = NULL;
3774     } else if (!js_CompileTokenStream(cx, obj, ts, &cg)) {
3775         script = NULL;
3776         eof = (ts->flags & TSF_EOF) != 0;
3777     } else {
3778         script = js_NewScriptFromCG(cx, &cg, NULL);
3779     }
3780     if (eofp)
3781         *eofp = eof;
3782     if (!js_CloseTokenStream(cx, ts)) {
3783         if (script)
3784             js_DestroyScript(cx, script);
3785         script = NULL;
3786     }
3787     cg.tempMark = tempMark;
3788     js_FinishCodeGenerator(cx, &cg);
3789     JS_FinishArenaPool(&codePool);
3790     JS_FinishArenaPool(&notePool);
3791     return script;
3792 }
3793 
3794 JS_PUBLIC_API(JSScript *)
JS_CompileScript(JSContext * cx,JSObject * obj,const char * bytes,size_t length,const char * filename,uintN lineno)3795 JS_CompileScript(JSContext *cx, JSObject *obj,
3796                  const char *bytes, size_t length,
3797                  const char *filename, uintN lineno)
3798 {
3799     jschar *chars;
3800     JSScript *script;
3801 
3802     CHECK_REQUEST(cx);
3803     chars = js_InflateString(cx, bytes, &length);
3804     if (!chars)
3805         return NULL;
3806     script = JS_CompileUCScript(cx, obj, chars, length, filename, lineno);
3807     JS_free(cx, chars);
3808     return script;
3809 }
3810 
3811 JS_PUBLIC_API(JSScript *)
JS_CompileScriptForPrincipals(JSContext * cx,JSObject * obj,JSPrincipals * principals,const char * bytes,size_t length,const char * filename,uintN lineno)3812 JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj,
3813                               JSPrincipals *principals,
3814                               const char *bytes, size_t length,
3815                               const char *filename, uintN lineno)
3816 {
3817     jschar *chars;
3818     JSScript *script;
3819 
3820     CHECK_REQUEST(cx);
3821     chars = js_InflateString(cx, bytes, &length);
3822     if (!chars)
3823         return NULL;
3824     script = JS_CompileUCScriptForPrincipals(cx, obj, principals,
3825                                              chars, length, filename, lineno);
3826     JS_free(cx, chars);
3827     return script;
3828 }
3829 
3830 JS_PUBLIC_API(JSScript *)
JS_CompileUCScript(JSContext * cx,JSObject * obj,const jschar * chars,size_t length,const char * filename,uintN lineno)3831 JS_CompileUCScript(JSContext *cx, JSObject *obj,
3832                    const jschar *chars, size_t length,
3833                    const char *filename, uintN lineno)
3834 {
3835     CHECK_REQUEST(cx);
3836     return JS_CompileUCScriptForPrincipals(cx, obj, NULL, chars, length,
3837                                            filename, lineno);
3838 }
3839 
3840 #define LAST_FRAME_EXCEPTION_CHECK(cx,result)                                 \
3841     JS_BEGIN_MACRO                                                            \
3842         if (!(result) && !((cx)->options & JSOPTION_DONT_REPORT_UNCAUGHT))    \
3843             js_ReportUncaughtException(cx);                                   \
3844     JS_END_MACRO
3845 
3846 #define LAST_FRAME_CHECKS(cx,result)                                          \
3847     JS_BEGIN_MACRO                                                            \
3848         if (!(cx)->fp) {                                                      \
3849             (cx)->weakRoots.lastInternalResult = JSVAL_NULL;                  \
3850             LAST_FRAME_EXCEPTION_CHECK(cx, result);                           \
3851         }                                                                     \
3852     JS_END_MACRO
3853 
3854 JS_PUBLIC_API(JSScript *)
JS_CompileUCScriptForPrincipals(JSContext * cx,JSObject * obj,JSPrincipals * principals,const jschar * chars,size_t length,const char * filename,uintN lineno)3855 JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj,
3856                                 JSPrincipals *principals,
3857                                 const jschar *chars, size_t length,
3858                                 const char *filename, uintN lineno)
3859 {
3860     void *mark;
3861     JSTokenStream *ts;
3862     JSScript *script;
3863 
3864     CHECK_REQUEST(cx);
3865     mark = JS_ARENA_MARK(&cx->tempPool);
3866     ts = js_NewTokenStream(cx, chars, length, filename, lineno, principals);
3867     if (!ts)
3868         return NULL;
3869     script = CompileTokenStream(cx, obj, ts, mark, NULL);
3870     LAST_FRAME_CHECKS(cx, script);
3871     return script;
3872 }
3873 
3874 JS_PUBLIC_API(JSBool)
JS_BufferIsCompilableUnit(JSContext * cx,JSObject * obj,const char * bytes,size_t length)3875 JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj,
3876                           const char *bytes, size_t length)
3877 {
3878     jschar *chars;
3879     JSBool result;
3880     JSExceptionState *exnState;
3881     void *tempMark;
3882     JSTokenStream *ts;
3883     JSErrorReporter older;
3884 
3885     CHECK_REQUEST(cx);
3886     chars = js_InflateString(cx, bytes, &length);
3887     if (!chars)
3888         return JS_TRUE;
3889 
3890     /*
3891      * Return true on any out-of-memory error, so our caller doesn't try to
3892      * collect more buffered source.
3893      */
3894     result = JS_TRUE;
3895     exnState = JS_SaveExceptionState(cx);
3896     tempMark = JS_ARENA_MARK(&cx->tempPool);
3897     ts = js_NewTokenStream(cx, chars, length, NULL, 0, NULL);
3898     if (ts) {
3899         older = JS_SetErrorReporter(cx, NULL);
3900         if (!js_ParseTokenStream(cx, obj, ts) &&
3901             (ts->flags & TSF_UNEXPECTED_EOF)) {
3902             /*
3903              * We ran into an error.  If it was because we ran out of source,
3904              * we return false, so our caller will know to try to collect more
3905              * buffered source.
3906              */
3907             result = JS_FALSE;
3908         }
3909 
3910         JS_SetErrorReporter(cx, older);
3911         js_CloseTokenStream(cx, ts);
3912         JS_ARENA_RELEASE(&cx->tempPool, tempMark);
3913     }
3914 
3915     JS_free(cx, chars);
3916     JS_RestoreExceptionState(cx, exnState);
3917     return result;
3918 }
3919 
3920 JS_PUBLIC_API(JSScript *)
JS_CompileFile(JSContext * cx,JSObject * obj,const char * filename)3921 JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
3922 {
3923     void *mark;
3924     JSTokenStream *ts;
3925     JSScript *script;
3926 
3927     CHECK_REQUEST(cx);
3928     mark = JS_ARENA_MARK(&cx->tempPool);
3929     ts = js_NewFileTokenStream(cx, filename, stdin);
3930     if (!ts)
3931         return NULL;
3932     script = CompileTokenStream(cx, obj, ts, mark, NULL);
3933     LAST_FRAME_CHECKS(cx, script);
3934     return script;
3935 }
3936 
3937 JS_PUBLIC_API(JSScript *)
JS_CompileFileHandle(JSContext * cx,JSObject * obj,const char * filename,FILE * file)3938 JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename,
3939                      FILE *file)
3940 {
3941     return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, NULL);
3942 }
3943 
3944 JS_PUBLIC_API(JSScript *)
JS_CompileFileHandleForPrincipals(JSContext * cx,JSObject * obj,const char * filename,FILE * file,JSPrincipals * principals)3945 JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj,
3946                                   const char *filename, FILE *file,
3947                                   JSPrincipals *principals)
3948 {
3949     void *mark;
3950     JSTokenStream *ts;
3951     JSScript *script;
3952 
3953     CHECK_REQUEST(cx);
3954     mark = JS_ARENA_MARK(&cx->tempPool);
3955     ts = js_NewFileTokenStream(cx, NULL, file);
3956     if (!ts)
3957         return NULL;
3958     ts->filename = filename;
3959     /* XXXshaver js_NewFileTokenStream should do this, because it drops */
3960     if (principals) {
3961         ts->principals = principals;
3962         JSPRINCIPALS_HOLD(cx, ts->principals);
3963     }
3964     script = CompileTokenStream(cx, obj, ts, mark, NULL);
3965     LAST_FRAME_CHECKS(cx, script);
3966     return script;
3967 }
3968 
3969 JS_PUBLIC_API(JSObject *)
JS_NewScriptObject(JSContext * cx,JSScript * script)3970 JS_NewScriptObject(JSContext *cx, JSScript *script)
3971 {
3972     JSObject *obj;
3973 
3974     obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL);
3975     if (!obj)
3976         return NULL;
3977 
3978     if (script) {
3979         if (!JS_SetPrivate(cx, obj, script))
3980             return NULL;
3981         script->object = obj;
3982     }
3983     return obj;
3984 }
3985 
3986 JS_PUBLIC_API(JSObject *)
JS_GetScriptObject(JSScript * script)3987 JS_GetScriptObject(JSScript *script)
3988 {
3989     return script->object;
3990 }
3991 
3992 JS_PUBLIC_API(void)
JS_DestroyScript(JSContext * cx,JSScript * script)3993 JS_DestroyScript(JSContext *cx, JSScript *script)
3994 {
3995     CHECK_REQUEST(cx);
3996     js_DestroyScript(cx, script);
3997 }
3998 
3999 JS_PUBLIC_API(JSFunction *)
JS_CompileFunction(JSContext * cx,JSObject * obj,const char * name,uintN nargs,const char ** argnames,const char * bytes,size_t length,const char * filename,uintN lineno)4000 JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name,
4001                    uintN nargs, const char **argnames,
4002                    const char *bytes, size_t length,
4003                    const char *filename, uintN lineno)
4004 {
4005     jschar *chars;
4006     JSFunction *fun;
4007 
4008     CHECK_REQUEST(cx);
4009     chars = js_InflateString(cx, bytes, &length);
4010     if (!chars)
4011         return NULL;
4012     fun = JS_CompileUCFunction(cx, obj, name, nargs, argnames, chars, length,
4013                                filename, lineno);
4014     JS_free(cx, chars);
4015     return fun;
4016 }
4017 
4018 JS_PUBLIC_API(JSFunction *)
JS_CompileFunctionForPrincipals(JSContext * cx,JSObject * obj,JSPrincipals * principals,const char * name,uintN nargs,const char ** argnames,const char * bytes,size_t length,const char * filename,uintN lineno)4019 JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj,
4020                                 JSPrincipals *principals, const char *name,
4021                                 uintN nargs, const char **argnames,
4022                                 const char *bytes, size_t length,
4023                                 const char *filename, uintN lineno)
4024 {
4025     jschar *chars;
4026     JSFunction *fun;
4027 
4028     CHECK_REQUEST(cx);
4029     chars = js_InflateString(cx, bytes, &length);
4030     if (!chars)
4031         return NULL;
4032     fun = JS_CompileUCFunctionForPrincipals(cx, obj, principals, name,
4033                                             nargs, argnames, chars, length,
4034                                             filename, lineno);
4035     JS_free(cx, chars);
4036     return fun;
4037 }
4038 
4039 JS_PUBLIC_API(JSFunction *)
JS_CompileUCFunction(JSContext * cx,JSObject * obj,const char * name,uintN nargs,const char ** argnames,const jschar * chars,size_t length,const char * filename,uintN lineno)4040 JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name,
4041                      uintN nargs, const char **argnames,
4042                      const jschar *chars, size_t length,
4043                      const char *filename, uintN lineno)
4044 {
4045     CHECK_REQUEST(cx);
4046     return JS_CompileUCFunctionForPrincipals(cx, obj, NULL, name,
4047                                              nargs, argnames,
4048                                              chars, length,
4049                                              filename, lineno);
4050 }
4051 
4052 JS_PUBLIC_API(JSFunction *)
JS_CompileUCFunctionForPrincipals(JSContext * cx,JSObject * obj,JSPrincipals * principals,const char * name,uintN nargs,const char ** argnames,const jschar * chars,size_t length,const char * filename,uintN lineno)4053 JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
4054                                   JSPrincipals *principals, const char *name,
4055                                   uintN nargs, const char **argnames,
4056                                   const jschar *chars, size_t length,
4057                                   const char *filename, uintN lineno)
4058 {
4059     void *mark;
4060     JSTokenStream *ts;
4061     JSFunction *fun;
4062     JSAtom *funAtom, *argAtom;
4063     uintN i;
4064 
4065     CHECK_REQUEST(cx);
4066     mark = JS_ARENA_MARK(&cx->tempPool);
4067     ts = js_NewTokenStream(cx, chars, length, filename, lineno, principals);
4068     if (!ts) {
4069         fun = NULL;
4070         goto out;
4071     }
4072     if (!name) {
4073         funAtom = NULL;
4074     } else {
4075         funAtom = js_Atomize(cx, name, strlen(name), 0);
4076         if (!funAtom) {
4077             fun = NULL;
4078             goto out;
4079         }
4080     }
4081     fun = js_NewFunction(cx, NULL, NULL, nargs, 0, obj, funAtom);
4082     if (!fun)
4083         goto out;
4084     if (nargs) {
4085         for (i = 0; i < nargs; i++) {
4086             argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
4087             if (!argAtom)
4088                 break;
4089             if (!js_AddHiddenProperty(cx, fun->object, ATOM_TO_JSID(argAtom),
4090                                       js_GetArgument, js_SetArgument,
4091                                       SPROP_INVALID_SLOT,
4092                                       JSPROP_PERMANENT | JSPROP_SHARED,
4093                                       SPROP_HAS_SHORTID, i)) {
4094                 break;
4095             }
4096         }
4097         if (i < nargs) {
4098             fun = NULL;
4099             goto out;
4100         }
4101     }
4102     if (!js_CompileFunctionBody(cx, ts, fun)) {
4103         fun = NULL;
4104         goto out;
4105     }
4106     if (obj && funAtom) {
4107         if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(funAtom),
4108                                  OBJECT_TO_JSVAL(fun->object),
4109                                  NULL, NULL, JSPROP_ENUMERATE, NULL)) {
4110             return NULL;
4111         }
4112     }
4113 out:
4114     if (ts)
4115         js_CloseTokenStream(cx, ts);
4116     JS_ARENA_RELEASE(&cx->tempPool, mark);
4117     LAST_FRAME_CHECKS(cx, fun);
4118     return fun;
4119 }
4120 
4121 JS_PUBLIC_API(JSString *)
JS_DecompileScript(JSContext * cx,JSScript * script,const char * name,uintN indent)4122 JS_DecompileScript(JSContext *cx, JSScript *script, const char *name,
4123                    uintN indent)
4124 {
4125     JSPrinter *jp;
4126     JSString *str;
4127 
4128     CHECK_REQUEST(cx);
4129     jp = js_NewPrinter(cx, name,
4130                        indent & ~JS_DONT_PRETTY_PRINT,
4131                        !(indent & JS_DONT_PRETTY_PRINT));
4132     if (!jp)
4133         return NULL;
4134     if (js_DecompileScript(jp, script))
4135         str = js_GetPrinterOutput(jp);
4136     else
4137         str = NULL;
4138     js_DestroyPrinter(jp);
4139     return str;
4140 }
4141 
4142 JS_PUBLIC_API(JSString *)
JS_DecompileFunction(JSContext * cx,JSFunction * fun,uintN indent)4143 JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent)
4144 {
4145     JSPrinter *jp;
4146     JSString *str;
4147 
4148     CHECK_REQUEST(cx);
4149     jp = js_NewPrinter(cx, JS_GetFunctionName(fun),
4150                        indent & ~JS_DONT_PRETTY_PRINT,
4151                        !(indent & JS_DONT_PRETTY_PRINT));
4152     if (!jp)
4153         return NULL;
4154     if (js_DecompileFunction(jp, fun))
4155         str = js_GetPrinterOutput(jp);
4156     else
4157         str = NULL;
4158     js_DestroyPrinter(jp);
4159     return str;
4160 }
4161 
4162 JS_PUBLIC_API(JSString *)
JS_DecompileFunctionBody(JSContext * cx,JSFunction * fun,uintN indent)4163 JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent)
4164 {
4165     JSPrinter *jp;
4166     JSString *str;
4167 
4168     CHECK_REQUEST(cx);
4169     jp = js_NewPrinter(cx, JS_GetFunctionName(fun),
4170                        indent & ~JS_DONT_PRETTY_PRINT,
4171                        !(indent & JS_DONT_PRETTY_PRINT));
4172     if (!jp)
4173         return NULL;
4174     if (js_DecompileFunctionBody(jp, fun))
4175         str = js_GetPrinterOutput(jp);
4176     else
4177         str = NULL;
4178     js_DestroyPrinter(jp);
4179     return str;
4180 }
4181 
4182 JS_PUBLIC_API(JSBool)
JS_ExecuteScript(JSContext * cx,JSObject * obj,JSScript * script,jsval * rval)4183 JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
4184 {
4185     JSBool ok;
4186 
4187     CHECK_REQUEST(cx);
4188     ok = js_Execute(cx, obj, script, NULL, 0, rval);
4189     LAST_FRAME_CHECKS(cx, ok);
4190     return ok;
4191 }
4192 
4193 JS_PUBLIC_API(JSBool)
JS_ExecuteScriptPart(JSContext * cx,JSObject * obj,JSScript * script,JSExecPart part,jsval * rval)4194 JS_ExecuteScriptPart(JSContext *cx, JSObject *obj, JSScript *script,
4195                      JSExecPart part, jsval *rval)
4196 {
4197     JSScript tmp;
4198     JSRuntime *rt;
4199     JSBool ok;
4200 
4201     /* Make a temporary copy of the JSScript structure and farble it a bit. */
4202     tmp = *script;
4203     if (part == JSEXEC_PROLOG) {
4204         tmp.length = PTRDIFF(tmp.main, tmp.code, jsbytecode);
4205     } else {
4206         tmp.length -= PTRDIFF(tmp.main, tmp.code, jsbytecode);
4207         tmp.code = tmp.main;
4208     }
4209 
4210     /* Tell the debugger about our temporary copy of the script structure. */
4211     rt = cx->runtime;
4212     if (rt->newScriptHook) {
4213         rt->newScriptHook(cx, tmp.filename, tmp.lineno, &tmp, NULL,
4214                           rt->newScriptHookData);
4215     }
4216 
4217     /* Execute the farbled struct and tell the debugger to forget about it. */
4218     ok = JS_ExecuteScript(cx, obj, &tmp, rval);
4219     if (rt->destroyScriptHook)
4220         rt->destroyScriptHook(cx, &tmp, rt->destroyScriptHookData);
4221     return ok;
4222 }
4223 
4224 /* Ancient uintN nbytes is part of API/ABI, so use size_t length local. */
4225 JS_PUBLIC_API(JSBool)
JS_EvaluateScript(JSContext * cx,JSObject * obj,const char * bytes,uintN nbytes,const char * filename,uintN lineno,jsval * rval)4226 JS_EvaluateScript(JSContext *cx, JSObject *obj,
4227                   const char *bytes, uintN nbytes,
4228                   const char *filename, uintN lineno,
4229                   jsval *rval)
4230 {
4231     size_t length = nbytes;
4232     jschar *chars;
4233     JSBool ok;
4234 
4235     CHECK_REQUEST(cx);
4236     chars = js_InflateString(cx, bytes, &length);
4237     if (!chars)
4238         return JS_FALSE;
4239     ok = JS_EvaluateUCScript(cx, obj, chars, length, filename, lineno, rval);
4240     JS_free(cx, chars);
4241     return ok;
4242 }
4243 
4244 /* Ancient uintN nbytes is part of API/ABI, so use size_t length local. */
4245 JS_PUBLIC_API(JSBool)
JS_EvaluateScriptForPrincipals(JSContext * cx,JSObject * obj,JSPrincipals * principals,const char * bytes,uintN nbytes,const char * filename,uintN lineno,jsval * rval)4246 JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj,
4247                                JSPrincipals *principals,
4248                                const char *bytes, uintN nbytes,
4249                                const char *filename, uintN lineno,
4250                                jsval *rval)
4251 {
4252     size_t length = nbytes;
4253     jschar *chars;
4254     JSBool ok;
4255 
4256     CHECK_REQUEST(cx);
4257     chars = js_InflateString(cx, bytes, &length);
4258     if (!chars)
4259         return JS_FALSE;
4260     ok = JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length,
4261                                           filename, lineno, rval);
4262     JS_free(cx, chars);
4263     return ok;
4264 }
4265 
4266 JS_PUBLIC_API(JSBool)
JS_EvaluateUCScript(JSContext * cx,JSObject * obj,const jschar * chars,uintN length,const char * filename,uintN lineno,jsval * rval)4267 JS_EvaluateUCScript(JSContext *cx, JSObject *obj,
4268                     const jschar *chars, uintN length,
4269                     const char *filename, uintN lineno,
4270                     jsval *rval)
4271 {
4272     CHECK_REQUEST(cx);
4273     return JS_EvaluateUCScriptForPrincipals(cx, obj, NULL, chars, length,
4274                                             filename, lineno, rval);
4275 }
4276 
4277 JS_PUBLIC_API(JSBool)
JS_EvaluateUCScriptForPrincipals(JSContext * cx,JSObject * obj,JSPrincipals * principals,const jschar * chars,uintN length,const char * filename,uintN lineno,jsval * rval)4278 JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
4279                                  JSPrincipals *principals,
4280                                  const jschar *chars, uintN length,
4281                                  const char *filename, uintN lineno,
4282                                  jsval *rval)
4283 {
4284     uint32 options;
4285     JSScript *script;
4286     JSBool ok;
4287 
4288     CHECK_REQUEST(cx);
4289     options = cx->options;
4290     cx->options = options | JSOPTION_COMPILE_N_GO;
4291     script = JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length,
4292                                              filename, lineno);
4293     cx->options = options;
4294     if (!script)
4295         return JS_FALSE;
4296     ok = js_Execute(cx, obj, script, NULL, 0, rval);
4297     LAST_FRAME_CHECKS(cx, ok);
4298     JS_DestroyScript(cx, script);
4299     return ok;
4300 }
4301 
4302 JS_PUBLIC_API(JSBool)
JS_CallFunction(JSContext * cx,JSObject * obj,JSFunction * fun,uintN argc,jsval * argv,jsval * rval)4303 JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc,
4304                 jsval *argv, jsval *rval)
4305 {
4306     JSBool ok;
4307 
4308     CHECK_REQUEST(cx);
4309     ok = js_InternalCall(cx, obj, OBJECT_TO_JSVAL(fun->object), argc, argv,
4310                          rval);
4311     LAST_FRAME_CHECKS(cx, ok);
4312     return ok;
4313 }
4314 
4315 JS_PUBLIC_API(JSBool)
JS_CallFunctionName(JSContext * cx,JSObject * obj,const char * name,uintN argc,jsval * argv,jsval * rval)4316 JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc,
4317                     jsval *argv, jsval *rval)
4318 {
4319     JSBool ok;
4320     jsval fval;
4321 
4322     CHECK_REQUEST(cx);
4323 #if JS_HAS_XML_SUPPORT
4324     if (OBJECT_IS_XML(cx, obj)) {
4325         JSXMLObjectOps *ops;
4326         JSAtom *atom;
4327 
4328         ops = (JSXMLObjectOps *) obj->map->ops;
4329         atom = js_Atomize(cx, name, strlen(name), 0);
4330         if (!atom)
4331             return JS_FALSE;
4332         obj = ops->getMethod(cx, obj, ATOM_TO_JSID(atom), &fval);
4333         if (!obj)
4334             return JS_FALSE;
4335     } else
4336 #endif
4337     if (!JS_GetProperty(cx, obj, name, &fval))
4338         return JS_FALSE;
4339     ok = js_InternalCall(cx, obj, fval, argc, argv, rval);
4340     LAST_FRAME_CHECKS(cx, ok);
4341     return ok;
4342 }
4343 
4344 JS_PUBLIC_API(JSBool)
JS_CallFunctionValue(JSContext * cx,JSObject * obj,jsval fval,uintN argc,jsval * argv,jsval * rval)4345 JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc,
4346                      jsval *argv, jsval *rval)
4347 {
4348     JSBool ok;
4349 
4350     CHECK_REQUEST(cx);
4351     ok = js_InternalCall(cx, obj, fval, argc, argv, rval);
4352     LAST_FRAME_CHECKS(cx, ok);
4353     return ok;
4354 }
4355 
4356 JS_PUBLIC_API(JSBranchCallback)
JS_SetBranchCallback(JSContext * cx,JSBranchCallback cb)4357 JS_SetBranchCallback(JSContext *cx, JSBranchCallback cb)
4358 {
4359     JSBranchCallback oldcb;
4360 
4361     oldcb = cx->branchCallback;
4362     cx->branchCallback = cb;
4363     return oldcb;
4364 }
4365 
4366 JS_PUBLIC_API(JSBool)
JS_IsRunning(JSContext * cx)4367 JS_IsRunning(JSContext *cx)
4368 {
4369     return cx->fp != NULL;
4370 }
4371 
4372 JS_PUBLIC_API(JSBool)
JS_IsConstructing(JSContext * cx)4373 JS_IsConstructing(JSContext *cx)
4374 {
4375     return cx->fp && (cx->fp->flags & JSFRAME_CONSTRUCTING);
4376 }
4377 
4378 JS_FRIEND_API(JSBool)
JS_IsAssigning(JSContext * cx)4379 JS_IsAssigning(JSContext *cx)
4380 {
4381     JSStackFrame *fp;
4382     jsbytecode *pc;
4383 
4384     for (fp = cx->fp; fp && !fp->script; fp = fp->down)
4385         continue;
4386     if (!fp || !(pc = fp->pc))
4387         return JS_FALSE;
4388     return (js_CodeSpec[*pc].format & JOF_ASSIGNING) != 0;
4389 }
4390 
4391 JS_PUBLIC_API(void)
JS_SetCallReturnValue2(JSContext * cx,jsval v)4392 JS_SetCallReturnValue2(JSContext *cx, jsval v)
4393 {
4394 #if JS_HAS_LVALUE_RETURN
4395     cx->rval2 = v;
4396     cx->rval2set = JS_TRUE;
4397 #endif
4398 }
4399 
4400 JS_PUBLIC_API(JSStackFrame *)
JS_SaveFrameChain(JSContext * cx)4401 JS_SaveFrameChain(JSContext *cx)
4402 {
4403     JSStackFrame *fp;
4404 
4405     fp = cx->fp;
4406     if (!fp)
4407         return fp;
4408 
4409     JS_ASSERT(!fp->dormantNext);
4410     fp->dormantNext = cx->dormantFrameChain;
4411     cx->dormantFrameChain = fp;
4412     cx->fp = NULL;
4413     return fp;
4414 }
4415 
4416 JS_PUBLIC_API(void)
JS_RestoreFrameChain(JSContext * cx,JSStackFrame * fp)4417 JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp)
4418 {
4419     JS_ASSERT(!cx->fp);
4420     if (!fp)
4421         return;
4422 
4423     JS_ASSERT(cx->dormantFrameChain == fp);
4424     cx->fp = fp;
4425     cx->dormantFrameChain = fp->dormantNext;
4426     fp->dormantNext = NULL;
4427 }
4428 
4429 /************************************************************************/
4430 
4431 JS_PUBLIC_API(JSString *)
JS_NewString(JSContext * cx,char * bytes,size_t nbytes)4432 JS_NewString(JSContext *cx, char *bytes, size_t nbytes)
4433 {
4434     size_t length = nbytes;
4435     jschar *chars;
4436     JSString *str;
4437 
4438     CHECK_REQUEST(cx);
4439 
4440     /* Make a UTF-16 vector from the 8-bit char codes in bytes. */
4441     chars = js_InflateString(cx, bytes, &length);
4442     if (!chars)
4443         return NULL;
4444 
4445     /* Free chars (but not bytes, which caller frees on error) if we fail. */
4446     str = js_NewString(cx, chars, length, 0);
4447     if (!str) {
4448         JS_free(cx, chars);
4449         return NULL;
4450     }
4451 
4452     /* Hand off bytes to the deflated string cache, if possible. */
4453     if (!js_SetStringBytes(cx->runtime, str, bytes, nbytes))
4454         JS_free(cx, bytes);
4455     return str;
4456 }
4457 
4458 JS_PUBLIC_API(JSString *)
JS_NewStringCopyN(JSContext * cx,const char * s,size_t n)4459 JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
4460 {
4461     jschar *js;
4462     JSString *str;
4463 
4464     CHECK_REQUEST(cx);
4465     js = js_InflateString(cx, s, &n);
4466     if (!js)
4467         return NULL;
4468     str = js_NewString(cx, js, n, 0);
4469     if (!str)
4470         JS_free(cx, js);
4471     return str;
4472 }
4473 
4474 JS_PUBLIC_API(JSString *)
JS_NewStringCopyZ(JSContext * cx,const char * s)4475 JS_NewStringCopyZ(JSContext *cx, const char *s)
4476 {
4477     size_t n;
4478     jschar *js;
4479     JSString *str;
4480 
4481     CHECK_REQUEST(cx);
4482     if (!s)
4483         return cx->runtime->emptyString;
4484     n = strlen(s);
4485     js = js_InflateString(cx, s, &n);
4486     if (!js)
4487         return NULL;
4488     str = js_NewString(cx, js, n, 0);
4489     if (!str)
4490         JS_free(cx, js);
4491     return str;
4492 }
4493 
4494 JS_PUBLIC_API(JSString *)
JS_InternString(JSContext * cx,const char * s)4495 JS_InternString(JSContext *cx, const char *s)
4496 {
4497     JSAtom *atom;
4498 
4499     CHECK_REQUEST(cx);
4500     atom = js_Atomize(cx, s, strlen(s), ATOM_INTERNED);
4501     if (!atom)
4502         return NULL;
4503     return ATOM_TO_STRING(atom);
4504 }
4505 
4506 JS_PUBLIC_API(JSString *)
JS_NewUCString(JSContext * cx,jschar * chars,size_t length)4507 JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
4508 {
4509     CHECK_REQUEST(cx);
4510     return js_NewString(cx, chars, length, 0);
4511 }
4512 
4513 JS_PUBLIC_API(JSString *)
JS_NewUCStringCopyN(JSContext * cx,const jschar * s,size_t n)4514 JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n)
4515 {
4516     CHECK_REQUEST(cx);
4517     return js_NewStringCopyN(cx, s, n, 0);
4518 }
4519 
4520 JS_PUBLIC_API(JSString *)
JS_NewUCStringCopyZ(JSContext * cx,const jschar * s)4521 JS_NewUCStringCopyZ(JSContext *cx, const jschar *s)
4522 {
4523     CHECK_REQUEST(cx);
4524     if (!s)
4525         return cx->runtime->emptyString;
4526     return js_NewStringCopyZ(cx, s, 0);
4527 }
4528 
4529 JS_PUBLIC_API(JSString *)
JS_InternUCStringN(JSContext * cx,const jschar * s,size_t length)4530 JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
4531 {
4532     JSAtom *atom;
4533 
4534     CHECK_REQUEST(cx);
4535     atom = js_AtomizeChars(cx, s, length, ATOM_INTERNED);
4536     if (!atom)
4537         return NULL;
4538     return ATOM_TO_STRING(atom);
4539 }
4540 
4541 JS_PUBLIC_API(JSString *)
JS_InternUCString(JSContext * cx,const jschar * s)4542 JS_InternUCString(JSContext *cx, const jschar *s)
4543 {
4544     return JS_InternUCStringN(cx, s, js_strlen(s));
4545 }
4546 
4547 JS_PUBLIC_API(char *)
JS_GetStringBytes(JSString * str)4548 JS_GetStringBytes(JSString *str)
4549 {
4550     JSRuntime *rt;
4551     char *bytes;
4552 
4553     rt = js_GetGCStringRuntime(str);
4554     bytes = js_GetStringBytes(rt, str);
4555     return bytes ? bytes : "";
4556 }
4557 
4558 JS_PUBLIC_API(jschar *)
JS_GetStringChars(JSString * str)4559 JS_GetStringChars(JSString *str)
4560 {
4561     /*
4562      * API botch (again, shades of JS_GetStringBytes): we have no cx to pass
4563      * to js_UndependString (called by js_GetStringChars) for out-of-memory
4564      * error reports, so js_UndependString passes NULL and suppresses errors.
4565      * If it fails to convert a dependent string into an independent one, our
4566      * caller will not be guaranteed a \u0000 terminator as a backstop.  This
4567      * may break some clients who already misbehave on embedded NULs.
4568      *
4569      * The gain of dependent strings, which cure quadratic and cubic growth
4570      * rate bugs in string concatenation, is worth this slight loss in API
4571      * compatibility.
4572      */
4573     jschar *chars;
4574 
4575     chars = js_GetStringChars(str);
4576     return chars ? chars : JSSTRING_CHARS(str);
4577 }
4578 
4579 JS_PUBLIC_API(size_t)
JS_GetStringLength(JSString * str)4580 JS_GetStringLength(JSString *str)
4581 {
4582     return JSSTRING_LENGTH(str);
4583 }
4584 
4585 JS_PUBLIC_API(intN)
JS_CompareStrings(JSString * str1,JSString * str2)4586 JS_CompareStrings(JSString *str1, JSString *str2)
4587 {
4588     return js_CompareStrings(str1, str2);
4589 }
4590 
4591 JS_PUBLIC_API(JSString *)
JS_NewGrowableString(JSContext * cx,jschar * chars,size_t length)4592 JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length)
4593 {
4594     CHECK_REQUEST(cx);
4595     return js_NewString(cx, chars, length, GCF_MUTABLE);
4596 }
4597 
4598 JS_PUBLIC_API(JSString *)
JS_NewDependentString(JSContext * cx,JSString * str,size_t start,size_t length)4599 JS_NewDependentString(JSContext *cx, JSString *str, size_t start,
4600                       size_t length)
4601 {
4602     CHECK_REQUEST(cx);
4603     return js_NewDependentString(cx, str, start, length, 0);
4604 }
4605 
4606 JS_PUBLIC_API(JSString *)
JS_ConcatStrings(JSContext * cx,JSString * left,JSString * right)4607 JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
4608 {
4609     CHECK_REQUEST(cx);
4610     return js_ConcatStrings(cx, left, right);
4611 }
4612 
4613 JS_PUBLIC_API(const jschar *)
JS_UndependString(JSContext * cx,JSString * str)4614 JS_UndependString(JSContext *cx, JSString *str)
4615 {
4616     CHECK_REQUEST(cx);
4617     return js_UndependString(cx, str);
4618 }
4619 
4620 JS_PUBLIC_API(JSBool)
JS_MakeStringImmutable(JSContext * cx,JSString * str)4621 JS_MakeStringImmutable(JSContext *cx, JSString *str)
4622 {
4623     CHECK_REQUEST(cx);
4624     if (!js_UndependString(cx, str))
4625         return JS_FALSE;
4626 
4627     *js_GetGCThingFlags(str) &= ~GCF_MUTABLE;
4628     return JS_TRUE;
4629 }
4630 
4631 JS_PUBLIC_API(JSBool)
JS_EncodeCharacters(JSContext * cx,const jschar * src,size_t srclen,char * dst,size_t * dstlenp)4632 JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst,
4633                     size_t *dstlenp)
4634 {
4635     return js_DeflateStringToBuffer(cx, src, srclen, dst, dstlenp);
4636 }
4637 
4638 JS_PUBLIC_API(JSBool)
JS_DecodeBytes(JSContext * cx,const char * src,size_t srclen,jschar * dst,size_t * dstlenp)4639 JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst,
4640                size_t *dstlenp)
4641 {
4642     return js_InflateStringToBuffer(cx, src, srclen, dst, dstlenp);
4643 }
4644 
4645 JS_PUBLIC_API(JSBool)
JS_CStringsAreUTF8()4646 JS_CStringsAreUTF8()
4647 {
4648 #ifdef JS_C_STRINGS_ARE_UTF8
4649     return JS_TRUE;
4650 #else
4651     return JS_FALSE;
4652 #endif
4653 }
4654 
4655 /************************************************************************/
4656 
4657 JS_PUBLIC_API(void)
JS_ReportError(JSContext * cx,const char * format,...)4658 JS_ReportError(JSContext *cx, const char *format, ...)
4659 {
4660     va_list ap;
4661 
4662     va_start(ap, format);
4663     js_ReportErrorVA(cx, JSREPORT_ERROR, format, ap);
4664     va_end(ap);
4665 }
4666 
4667 JS_PUBLIC_API(void)
JS_ReportErrorNumber(JSContext * cx,JSErrorCallback errorCallback,void * userRef,const uintN errorNumber,...)4668 JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback,
4669                      void *userRef, const uintN errorNumber, ...)
4670 {
4671     va_list ap;
4672 
4673     va_start(ap, errorNumber);
4674     js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
4675                            errorNumber, JS_TRUE, ap);
4676     va_end(ap);
4677 }
4678 
4679 JS_PUBLIC_API(void)
JS_ReportErrorNumberUC(JSContext * cx,JSErrorCallback errorCallback,void * userRef,const uintN errorNumber,...)4680 JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
4681                      void *userRef, const uintN errorNumber, ...)
4682 {
4683     va_list ap;
4684 
4685     va_start(ap, errorNumber);
4686     js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
4687                            errorNumber, JS_FALSE, ap);
4688     va_end(ap);
4689 }
4690 
4691 JS_PUBLIC_API(JSBool)
JS_ReportWarning(JSContext * cx,const char * format,...)4692 JS_ReportWarning(JSContext *cx, const char *format, ...)
4693 {
4694     va_list ap;
4695     JSBool ok;
4696 
4697     va_start(ap, format);
4698     ok = js_ReportErrorVA(cx, JSREPORT_WARNING, format, ap);
4699     va_end(ap);
4700     return ok;
4701 }
4702 
4703 JS_PUBLIC_API(JSBool)
JS_ReportErrorFlagsAndNumber(JSContext * cx,uintN flags,JSErrorCallback errorCallback,void * userRef,const uintN errorNumber,...)4704 JS_ReportErrorFlagsAndNumber(JSContext *cx, uintN flags,
4705                              JSErrorCallback errorCallback, void *userRef,
4706                              const uintN errorNumber, ...)
4707 {
4708     va_list ap;
4709     JSBool ok;
4710 
4711     va_start(ap, errorNumber);
4712     ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
4713                                 errorNumber, JS_TRUE, ap);
4714     va_end(ap);
4715     return ok;
4716 }
4717 
4718 JS_PUBLIC_API(JSBool)
JS_ReportErrorFlagsAndNumberUC(JSContext * cx,uintN flags,JSErrorCallback errorCallback,void * userRef,const uintN errorNumber,...)4719 JS_ReportErrorFlagsAndNumberUC(JSContext *cx, uintN flags,
4720                                JSErrorCallback errorCallback, void *userRef,
4721                                const uintN errorNumber, ...)
4722 {
4723     va_list ap;
4724     JSBool ok;
4725 
4726     va_start(ap, errorNumber);
4727     ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
4728                                 errorNumber, JS_FALSE, ap);
4729     va_end(ap);
4730     return ok;
4731 }
4732 
4733 JS_PUBLIC_API(void)
JS_ReportOutOfMemory(JSContext * cx)4734 JS_ReportOutOfMemory(JSContext *cx)
4735 {
4736     js_ReportOutOfMemory(cx);
4737 }
4738 
4739 JS_PUBLIC_API(JSErrorReporter)
JS_SetErrorReporter(JSContext * cx,JSErrorReporter er)4740 JS_SetErrorReporter(JSContext *cx, JSErrorReporter er)
4741 {
4742     JSErrorReporter older;
4743 
4744     older = cx->errorReporter;
4745     cx->errorReporter = er;
4746     return older;
4747 }
4748 
4749 /************************************************************************/
4750 
4751 /*
4752  * Regular Expressions.
4753  */
4754 JS_PUBLIC_API(JSObject *)
JS_NewRegExpObject(JSContext * cx,char * bytes,size_t length,uintN flags)4755 JS_NewRegExpObject(JSContext *cx, char *bytes, size_t length, uintN flags)
4756 {
4757     jschar *chars;
4758     JSObject *obj;
4759 
4760     CHECK_REQUEST(cx);
4761     chars = js_InflateString(cx, bytes, &length);
4762     if (!chars)
4763         return NULL;
4764     obj = js_NewRegExpObject(cx, NULL, chars, length, flags);
4765     JS_free(cx, chars);
4766     return obj;
4767 }
4768 
4769 JS_PUBLIC_API(JSObject *)
JS_NewUCRegExpObject(JSContext * cx,jschar * chars,size_t length,uintN flags)4770 JS_NewUCRegExpObject(JSContext *cx, jschar *chars, size_t length, uintN flags)
4771 {
4772     CHECK_REQUEST(cx);
4773     return js_NewRegExpObject(cx, NULL, chars, length, flags);
4774 }
4775 
4776 JS_PUBLIC_API(void)
JS_SetRegExpInput(JSContext * cx,JSString * input,JSBool multiline)4777 JS_SetRegExpInput(JSContext *cx, JSString *input, JSBool multiline)
4778 {
4779     JSRegExpStatics *res;
4780 
4781     CHECK_REQUEST(cx);
4782     /* No locking required, cx is thread-private and input must be live. */
4783     res = &cx->regExpStatics;
4784     res->input = input;
4785     res->multiline = multiline;
4786     cx->runtime->gcPoke = JS_TRUE;
4787 }
4788 
4789 JS_PUBLIC_API(void)
JS_ClearRegExpStatics(JSContext * cx)4790 JS_ClearRegExpStatics(JSContext *cx)
4791 {
4792     JSRegExpStatics *res;
4793 
4794     /* No locking required, cx is thread-private and input must be live. */
4795     res = &cx->regExpStatics;
4796     res->input = NULL;
4797     res->multiline = JS_FALSE;
4798     res->parenCount = 0;
4799     res->lastMatch = res->lastParen = js_EmptySubString;
4800     res->leftContext = res->rightContext = js_EmptySubString;
4801     cx->runtime->gcPoke = JS_TRUE;
4802 }
4803 
4804 JS_PUBLIC_API(void)
JS_ClearRegExpRoots(JSContext * cx)4805 JS_ClearRegExpRoots(JSContext *cx)
4806 {
4807     JSRegExpStatics *res;
4808 
4809     /* No locking required, cx is thread-private and input must be live. */
4810     res = &cx->regExpStatics;
4811     res->input = NULL;
4812     cx->runtime->gcPoke = JS_TRUE;
4813 }
4814 
4815 /* TODO: compile, execute, get/set other statics... */
4816 
4817 /************************************************************************/
4818 
4819 JS_PUBLIC_API(void)
JS_SetLocaleCallbacks(JSContext * cx,JSLocaleCallbacks * callbacks)4820 JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks)
4821 {
4822     cx->localeCallbacks = callbacks;
4823 }
4824 
4825 JS_PUBLIC_API(JSLocaleCallbacks *)
JS_GetLocaleCallbacks(JSContext * cx)4826 JS_GetLocaleCallbacks(JSContext *cx)
4827 {
4828     return cx->localeCallbacks;
4829 }
4830 
4831 /************************************************************************/
4832 
4833 JS_PUBLIC_API(JSBool)
JS_IsExceptionPending(JSContext * cx)4834 JS_IsExceptionPending(JSContext *cx)
4835 {
4836     return (JSBool) cx->throwing;
4837 }
4838 
4839 JS_PUBLIC_API(JSBool)
JS_GetPendingException(JSContext * cx,jsval * vp)4840 JS_GetPendingException(JSContext *cx, jsval *vp)
4841 {
4842     CHECK_REQUEST(cx);
4843     if (!cx->throwing)
4844         return JS_FALSE;
4845     *vp = cx->exception;
4846     return JS_TRUE;
4847 }
4848 
4849 JS_PUBLIC_API(void)
JS_SetPendingException(JSContext * cx,jsval v)4850 JS_SetPendingException(JSContext *cx, jsval v)
4851 {
4852     CHECK_REQUEST(cx);
4853     cx->throwing = JS_TRUE;
4854     cx->exception = v;
4855 }
4856 
4857 JS_PUBLIC_API(void)
JS_ClearPendingException(JSContext * cx)4858 JS_ClearPendingException(JSContext *cx)
4859 {
4860     cx->throwing = JS_FALSE;
4861     cx->exception = JSVAL_VOID;
4862 }
4863 
4864 JS_PUBLIC_API(JSBool)
JS_ReportPendingException(JSContext * cx)4865 JS_ReportPendingException(JSContext *cx)
4866 {
4867     JSBool save, ok;
4868 
4869     CHECK_REQUEST(cx);
4870 
4871     /*
4872      * Set cx->creatingException to suppress the standard error-to-exception
4873      * conversion done by all {js,JS}_Report* functions except for OOM.  The
4874      * cx->creatingException flag was added to suppress recursive divergence
4875      * under js_ErrorToException, but it serves for our purposes here too.
4876      */
4877     save = cx->creatingException;
4878     cx->creatingException = JS_TRUE;
4879     ok = js_ReportUncaughtException(cx);
4880     cx->creatingException = save;
4881     return ok;
4882 }
4883 
4884 struct JSExceptionState {
4885     JSBool throwing;
4886     jsval  exception;
4887 };
4888 
4889 JS_PUBLIC_API(JSExceptionState *)
JS_SaveExceptionState(JSContext * cx)4890 JS_SaveExceptionState(JSContext *cx)
4891 {
4892     JSExceptionState *state;
4893 
4894     CHECK_REQUEST(cx);
4895     state = (JSExceptionState *) JS_malloc(cx, sizeof(JSExceptionState));
4896     if (state) {
4897         state->throwing = JS_GetPendingException(cx, &state->exception);
4898         if (state->throwing && JSVAL_IS_GCTHING(state->exception))
4899             js_AddRoot(cx, &state->exception, "JSExceptionState.exception");
4900     }
4901     return state;
4902 }
4903 
4904 JS_PUBLIC_API(void)
JS_RestoreExceptionState(JSContext * cx,JSExceptionState * state)4905 JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state)
4906 {
4907     CHECK_REQUEST(cx);
4908     if (state) {
4909         if (state->throwing)
4910             JS_SetPendingException(cx, state->exception);
4911         else
4912             JS_ClearPendingException(cx);
4913         JS_DropExceptionState(cx, state);
4914     }
4915 }
4916 
4917 JS_PUBLIC_API(void)
JS_DropExceptionState(JSContext * cx,JSExceptionState * state)4918 JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
4919 {
4920     CHECK_REQUEST(cx);
4921     if (state) {
4922         if (state->throwing && JSVAL_IS_GCTHING(state->exception))
4923             JS_RemoveRoot(cx, &state->exception);
4924         JS_free(cx, state);
4925     }
4926 }
4927 
4928 JS_PUBLIC_API(JSErrorReport *)
JS_ErrorFromException(JSContext * cx,jsval v)4929 JS_ErrorFromException(JSContext *cx, jsval v)
4930 {
4931     CHECK_REQUEST(cx);
4932     return js_ErrorFromException(cx, v);
4933 }
4934 
4935 JS_PUBLIC_API(JSBool)
JS_ThrowReportedError(JSContext * cx,const char * message,JSErrorReport * reportp)4936 JS_ThrowReportedError(JSContext *cx, const char *message,
4937                       JSErrorReport *reportp)
4938 {
4939     return js_ErrorToException(cx, message, reportp);
4940 }
4941 
4942 #ifdef JS_THREADSAFE
4943 /*
4944  * Get the owning thread id of a context. Returns 0 if the context is not
4945  * owned by any thread.
4946  */
4947 JS_PUBLIC_API(jsword)
JS_GetContextThread(JSContext * cx)4948 JS_GetContextThread(JSContext *cx)
4949 {
4950     return JS_THREAD_ID(cx);
4951 }
4952 
4953 /*
4954  * Set the current thread as the owning thread of a context. Returns the
4955  * old owning thread id, or -1 if the operation failed.
4956  */
4957 JS_PUBLIC_API(jsword)
JS_SetContextThread(JSContext * cx)4958 JS_SetContextThread(JSContext *cx)
4959 {
4960     jsword old = JS_THREAD_ID(cx);
4961     if (!js_SetContextThread(cx))
4962         return -1;
4963     return old;
4964 }
4965 
4966 JS_PUBLIC_API(jsword)
JS_ClearContextThread(JSContext * cx)4967 JS_ClearContextThread(JSContext *cx)
4968 {
4969     jsword old = JS_THREAD_ID(cx);
4970     js_ClearContextThread(cx);
4971     return old;
4972 }
4973 #endif
4974 
4975 /************************************************************************/
4976 
4977 #if defined(XP_WIN)
4978 #include <windows.h>
4979 /*
4980  * Initialization routine for the JS DLL...
4981  */
4982 
4983 /*
4984  * Global Instance handle...
4985  * In Win32 this is the module handle of the DLL.
4986  *
4987  * In Win16 this is the instance handle of the application
4988  * which loaded the DLL.
4989  */
4990 
4991 #ifdef _WIN32
DllMain(HINSTANCE hDLL,DWORD dwReason,LPVOID lpReserved)4992 BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
4993 {
4994     return TRUE;
4995 }
4996 
4997 #else  /* !_WIN32 */
4998 
LibMain(HINSTANCE hInst,WORD wDataSeg,WORD cbHeapSize,LPSTR lpszCmdLine)4999 int CALLBACK LibMain( HINSTANCE hInst, WORD wDataSeg,
5000                       WORD cbHeapSize, LPSTR lpszCmdLine )
5001 {
5002     return TRUE;
5003 }
5004 
WEP(BOOL fSystemExit)5005 BOOL CALLBACK __loadds WEP(BOOL fSystemExit)
5006 {
5007     return TRUE;
5008 }
5009 
5010 #endif /* !_WIN32 */
5011 #endif /* XP_WIN */
5012