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(¬ePool, "note", 1024, sizeof(jssrcnote));
3770 if (!js_InitCodeGenerator(cx, &cg, &codePool, ¬ePool,
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(¬ePool);
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