1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 *
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 *
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
10 *
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
15 *
16 * The Original Code is Mozilla Communicator client code, released
17 * March 31, 1998.
18 *
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1998
22 * the Initial Developer. All Rights Reserved.
23 *
24 * Contributor(s):
25 *
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
37 *
38 * ***** END LICENSE BLOCK ***** */
40 /*
41 * JavaScript API.
42 */
43 #include "jsstddef.h"
44 #include <ctype.h>
45 #include <stdarg.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include "jstypes.h"
49 #include "jsarena.h" /* Added by JSIFY */
50 #include "jsutil.h" /* Added by JSIFY */
51 #include "jsclist.h"
52 #include "jsdhash.h"
53 #include "jsprf.h"
54 #include "jsapi.h"
55 #include "jsarray.h"
56 #include "jsatom.h"
57 #include "jsbool.h"
58 #include "jscntxt.h"
59 #include "jsconfig.h"
60 #include "jsdate.h"
61 #include "jsdtoa.h"
62 #include "jsemit.h"
63 #include "jsexn.h"
64 #include "jsfun.h"
65 #include "jsgc.h"
66 #include "jsinterp.h"
67 #include "jslock.h"
68 #include "jsmath.h"
69 #include "jsnum.h"
70 #include "jsobj.h"
71 #include "jsopcode.h"
72 #include "jsparse.h"
73 #include "jsregexp.h"
74 #include "jsscan.h"
75 #include "jsscope.h"
76 #include "jsscript.h"
77 #include "jsstr.h"
78 #include "prmjtime.h"
80 #if JS_HAS_FILE_OBJECT
81 #include "jsfile.h"
82 #endif
84 #ifdef HAVE_VA_LIST_AS_ARRAY
85 #define JS_ADDRESSOF_VA_LIST(ap) (ap)
86 #else
87 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
88 #endif
90 #if defined(JS_PARANOID_REQUEST) && defined(JS_THREADSAFE)
91 #define CHECK_REQUEST(cx) JS_ASSERT(cx->requestDepth)
92 #else
93 #define CHECK_REQUEST(cx) ((void)0)
94 #endif
96 JS_PUBLIC_API(int64)
97 JS_Now()
98 {
99 return PRMJ_Now();
100 }
102 JS_PUBLIC_API(jsval)
103 JS_GetNaNValue(JSContext *cx)
104 {
105 return DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
106 }
108 JS_PUBLIC_API(jsval)
109 JS_GetNegativeInfinityValue(JSContext *cx)
110 {
111 return DOUBLE_TO_JSVAL(cx->runtime->jsNegativeInfinity);
112 }
114 JS_PUBLIC_API(jsval)
115 JS_GetPositiveInfinityValue(JSContext *cx)
116 {
117 return DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
118 }
120 JS_PUBLIC_API(jsval)
121 JS_GetEmptyStringValue(JSContext *cx)
122 {
123 return STRING_TO_JSVAL(cx->runtime->emptyString);
124 }
126 static JSBool
127 TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS,
128 jsval **vpp, va_list *app)
129 {
130 const char *format;
131 JSArgumentFormatMap *map;
133 format = *formatp;
134 for (map = cx->argumentFormatMap; map; map = map->next) {
135 if (!strncmp(format, map->format, map->length)) {
136 *formatp = format + map->length;
137 return map->formatter(cx, format, fromJS, vpp, app);
138 }
139 }
140 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
141 return JS_FALSE;
142 }
144 JS_PUBLIC_API(JSBool)
145 JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format,
146 ...)
147 {
148 va_list ap;
149 JSBool ok;
151 va_start(ap, format);
152 ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap);
153 va_end(ap);
154 return ok;
155 }
157 JS_PUBLIC_API(JSBool)
158 JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv,
159 const char *format, va_list ap)
160 {
161 jsval *sp;
162 JSBool required;
163 char c;
164 JSFunction *fun;
165 jsdouble d;
166 JSString *str;
167 JSObject *obj;
169 CHECK_REQUEST(cx);
170 sp = argv;
171 required = JS_TRUE;
172 while ((c = *format++) != '\0') {
173 if (isspace(c))
174 continue;
175 if (c == '/') {
176 required = JS_FALSE;
177 continue;
178 }
179 if (sp == argv + argc) {
180 if (required) {
181 fun = js_ValueToFunction(cx, &argv[-2], 0);
182 if (fun) {
183 char numBuf[12];
184 JS_snprintf(numBuf, sizeof numBuf, "%u", argc);
185 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
186 JSMSG_MORE_ARGS_NEEDED,
187 JS_GetFunctionName(fun), numBuf,
188 (argc == 1) ? "" : "s");
189 }
190 return JS_FALSE;
191 }
192 break;
193 }
194 switch (c) {
195 case 'b':
196 if (!js_ValueToBoolean(cx, *sp, va_arg(ap, JSBool *)))
197 return JS_FALSE;
198 break;
199 case 'c':
200 if (!js_ValueToUint16(cx, *sp, va_arg(ap, uint16 *)))
201 return JS_FALSE;
202 break;
203 case 'i':
204 if (!js_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *)))
205 return JS_FALSE;
206 break;
207 case 'u':
208 if (!js_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *)))
209 return JS_FALSE;
210 break;
211 case 'j':
212 if (!js_ValueToInt32(cx, *sp, va_arg(ap, int32 *)))
213 return JS_FALSE;
214 break;
215 case 'd':
216 if (!js_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *)))
217 return JS_FALSE;
218 break;
219 case 'I':
220 if (!js_ValueToNumber(cx, *sp, &d))
221 return JS_FALSE;
222 *va_arg(ap, jsdouble *) = js_DoubleToInteger(d);
223 break;
224 case 's':
225 case 'S':
226 case 'W':
227 str = js_ValueToString(cx, *sp);
228 if (!str)
229 return JS_FALSE;
230 *sp = STRING_TO_JSVAL(str);
231 if (c == 's')
232 *va_arg(ap, char **) = JS_GetStringBytes(str);
233 else if (c == 'W')
234 *va_arg(ap, jschar **) = JS_GetStringChars(str);
235 else
236 *va_arg(ap, JSString **) = str;
237 break;
238 case 'o':
239 if (!js_ValueToObject(cx, *sp, &obj))
240 return JS_FALSE;
241 *sp = OBJECT_TO_JSVAL(obj);
242 *va_arg(ap, JSObject **) = obj;
243 break;
244 case 'f':
245 /*
246 * Don't convert a cloned function object to its shared private
247 * data, then follow fun->object back to the clone-parent.
248 */
249 if (JSVAL_IS_FUNCTION(cx, *sp)) {
250 fun = (JSFunction *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(*sp));
251 } else {
252 fun = js_ValueToFunction(cx, sp, 0);
253 if (!fun)
254 return JS_FALSE;
255 *sp = OBJECT_TO_JSVAL(fun->object);
256 }
257 *va_arg(ap, JSFunction **) = fun;
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 }
278 JS_PUBLIC_API(jsval *)
279 JS_PushArguments(JSContext *cx, void **markp, const char *format, ...)
280 {
281 va_list ap;
282 jsval *argv;
284 va_start(ap, format);
285 argv = JS_PushArgumentsVA(cx, markp, format, ap);
286 va_end(ap);
287 return argv;
288 }
290 JS_PUBLIC_API(jsval *)
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;
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 }
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;
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;
395 bad:
396 js_FreeStack(cx, *markp);
397 return NULL;
398 }
400 JS_PUBLIC_API(void)
401 JS_PopArguments(JSContext *cx, void *mark)
402 {
403 CHECK_REQUEST(cx);
404 js_FreeStack(cx, mark);
405 }
407 JS_PUBLIC_API(JSBool)
408 JS_AddArgumentFormatter(JSContext *cx, const char *format,
409 JSArgumentFormatter formatter)
410 {
411 size_t length;
412 JSArgumentFormatMap **mpp, *map;
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 }
436 JS_PUBLIC_API(void)
437 JS_RemoveArgumentFormatter(JSContext *cx, const char *format)
438 {
439 size_t length;
440 JSArgumentFormatMap **mpp, *map;
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 }
454 JS_PUBLIC_API(JSBool)
455 JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
456 {
457 JSBool ok, b;
458 JSObject *obj;
459 JSFunction *fun;
460 JSString *str;
461 jsdouble d, *dp;
463 CHECK_REQUEST(cx);
464 switch (type) {
465 case JSTYPE_VOID:
466 *vp = JSVAL_VOID;
467 ok = JS_TRUE;
468 break;
469 case JSTYPE_OBJECT:
470 ok = js_ValueToObject(cx, v, &obj);
471 if (ok)
472 *vp = OBJECT_TO_JSVAL(obj);
473 break;
474 case JSTYPE_FUNCTION:
475 /*
476 * Don't convert a cloned function object to its shared private data,
477 * then follow fun->object back to the clone-parent.
478 */
479 if (JSVAL_IS_FUNCTION(cx, v)) {
480 ok = JS_TRUE;
481 *vp = v;
482 } else {
483 fun = js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
484 ok = (fun != NULL);
485 if (ok)
486 *vp = OBJECT_TO_JSVAL(fun->object);
487 }
488 break;
489 case JSTYPE_STRING:
490 str = js_ValueToString(cx, v);
491 ok = (str != NULL);
492 if (ok)
493 *vp = STRING_TO_JSVAL(str);
494 break;
495 case JSTYPE_NUMBER:
496 ok = js_ValueToNumber(cx, v, &d);
497 if (ok) {
498 dp = js_NewDouble(cx, d);
499 ok = (dp != NULL);
500 if (ok)
501 *vp = DOUBLE_TO_JSVAL(dp);
502 }
503 break;
504 case JSTYPE_BOOLEAN:
505 ok = js_ValueToBoolean(cx, v, &b);
506 if (ok)
507 *vp = BOOLEAN_TO_JSVAL(b);
508 break;
509 default: {
510 char numBuf[12];
511 JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
512 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE,
513 numBuf);
514 ok = JS_FALSE;
515 break;
516 }
517 }
518 return ok;
519 }
521 JS_PUBLIC_API(JSBool)
522 JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp)
523 {
524 CHECK_REQUEST(cx);
525 return js_ValueToObject(cx, v, objp);
526 }
528 JS_PUBLIC_API(JSFunction *)
529 JS_ValueToFunction(JSContext *cx, jsval v)
530 {
531 CHECK_REQUEST(cx);
532 return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
533 }
535 JS_PUBLIC_API(JSFunction *)
536 JS_ValueToConstructor(JSContext *cx, jsval v)
537 {
538 CHECK_REQUEST(cx);
539 return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
540 }
542 JS_PUBLIC_API(JSString *)
543 JS_ValueToString(JSContext *cx, jsval v)
544 {
545 CHECK_REQUEST(cx);
546 return js_ValueToString(cx, v);
547 }
549 JS_PUBLIC_API(JSBool)
550 JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
551 {
552 CHECK_REQUEST(cx);
553 return js_ValueToNumber(cx, v, dp);
554 }
556 JS_PUBLIC_API(JSBool)
557 JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
558 {
559 CHECK_REQUEST(cx);
560 return js_ValueToECMAInt32(cx, v, ip);
561 }
563 JS_PUBLIC_API(JSBool)
564 JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
565 {
566 CHECK_REQUEST(cx);
567 return js_ValueToECMAUint32(cx, v, ip);
568 }
570 JS_PUBLIC_API(JSBool)
571 JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
572 {
573 CHECK_REQUEST(cx);
574 return js_ValueToInt32(cx, v, ip);
575 }
577 JS_PUBLIC_API(JSBool)
578 JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
579 {
580 CHECK_REQUEST(cx);
581 return js_ValueToUint16(cx, v, ip);
582 }
584 JS_PUBLIC_API(JSBool)
585 JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
586 {
587 CHECK_REQUEST(cx);
588 return js_ValueToBoolean(cx, v, bp);
589 }
591 JS_PUBLIC_API(JSType)
592 JS_TypeOfValue(JSContext *cx, jsval v)
593 {
594 JSType type;
595 JSObject *obj;
596 JSObjectOps *ops;
597 JSClass *clasp;
599 CHECK_REQUEST(cx);
600 if (JSVAL_IS_OBJECT(v)) {
601 /* XXX JSVAL_IS_OBJECT(v) is true for null too! Can we change ECMA? */
602 obj = JSVAL_TO_OBJECT(v);
603 if (obj &&
604 (ops = obj->map->ops,
605 ops == &js_ObjectOps
606 ? (clasp = OBJ_GET_CLASS(cx, obj),
607 clasp->call || clasp == &js_FunctionClass)
608 : ops->call != NULL)) {
609 type = JSTYPE_FUNCTION;
610 } else {
611 #ifdef NARCISSUS
612 if (obj) {
613 /* XXX suppress errors/exceptions */
614 OBJ_GET_PROPERTY(cx, obj,
615 (jsid)cx->runtime->atomState.callAtom,
616 &v);
617 if (JSVAL_IS_FUNCTION(cx, v))
618 return JSTYPE_FUNCTION;
619 }
620 #endif
621 type = JSTYPE_OBJECT;
622 }
623 } else if (JSVAL_IS_NUMBER(v)) {
624 type = JSTYPE_NUMBER;
625 } else if (JSVAL_IS_STRING(v)) {
626 type = JSTYPE_STRING;
627 } else if (JSVAL_IS_BOOLEAN(v)) {
628 type = JSTYPE_BOOLEAN;
629 } else {
630 type = JSTYPE_VOID;
631 }
632 return type;
633 }
635 JS_PUBLIC_API(const char *)
636 JS_GetTypeName(JSContext *cx, JSType type)
637 {
638 if ((uintN)type >= (uintN)JSTYPE_LIMIT)
639 return NULL;
640 return js_type_str[type];
641 }
643 /************************************************************************/
645 JS_PUBLIC_API(JSRuntime *)
646 JS_NewRuntime(uint32 maxbytes)
647 {
648 JSRuntime *rt;
650 #ifdef DEBUG
651 JS_BEGIN_MACRO
652 /*
653 * This code asserts that the numbers associated with the error names in
654 * jsmsg.def are monotonically increasing. It uses values for the error
655 * names enumerated in jscntxt.c. It's not a compiletime check, but it's
656 * better than nothing.
657 */
658 int errorNumber = 0;
659 #define MSG_DEF(name, number, count, exception, format) \
660 JS_ASSERT(name == errorNumber++);
661 #include "js.msg"
662 #undef MSG_DEF
663 JS_END_MACRO;
664 #endif /* DEBUG */
666 if (!js_InitStringGlobals())
667 return NULL;
668 rt = (JSRuntime *) malloc(sizeof(JSRuntime));
669 if (!rt)
670 return NULL;
672 /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
673 memset(rt, 0, sizeof(JSRuntime));
674 JS_INIT_CLIST(&rt->contextList);
675 JS_INIT_CLIST(&rt->trapList);
676 JS_INIT_CLIST(&rt->watchPointList);
678 if (!js_InitGC(rt, maxbytes))
679 goto bad;
680 #ifdef JS_THREADSAFE
681 rt->gcLock = JS_NEW_LOCK();
682 if (!rt->gcLock)
683 goto bad;
684 rt->gcDone = JS_NEW_CONDVAR(rt->gcLock);
685 if (!rt->gcDone)
686 goto bad;
687 rt->requestDone = JS_NEW_CONDVAR(rt->gcLock);
688 if (!rt->requestDone)
689 goto bad;
690 js_SetupLocks(8, 16); /* this is asymmetric with JS_ShutDown. */
691 rt->rtLock = JS_NEW_LOCK();
692 if (!rt->rtLock)
693 goto bad;
694 rt->stateChange = JS_NEW_CONDVAR(rt->gcLock);
695 if (!rt->stateChange)
696 goto bad;
697 rt->setSlotLock = JS_NEW_LOCK();
698 if (!rt->setSlotLock)
699 goto bad;
700 rt->setSlotDone = JS_NEW_CONDVAR(rt->setSlotLock);
701 if (!rt->setSlotDone)
702 goto bad;
703 rt->scopeSharingDone = JS_NEW_CONDVAR(rt->gcLock);
704 if (!rt->scopeSharingDone)
705 goto bad;
706 rt->scopeSharingTodo = NO_SCOPE_SHARING_TODO;
707 #endif
708 rt->propertyCache.empty = JS_TRUE;
709 if (!js_InitPropertyTree(rt))
710 goto bad;
711 return rt;
713 bad:
714 JS_DestroyRuntime(rt);
715 return NULL;
716 }
718 JS_PUBLIC_API(void)
719 JS_DestroyRuntime(JSRuntime *rt)
720 {
721 #ifdef DEBUG
722 /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */
723 if (!JS_CLIST_IS_EMPTY(&rt->contextList)) {
724 JSContext *cx, *iter = NULL;
725 uintN cxcount = 0;
726 while ((cx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL)
727 cxcount++;
728 fprintf(stderr,
729 "JS API usage error: %u contexts left in runtime upon JS_DestroyRuntime.\n",
730 cxcount);
731 }
732 #endif
734 js_FinishAtomState(&rt->atomState);
735 js_FinishGC(rt);
736 #ifdef JS_THREADSAFE
737 if (rt->gcLock)
738 JS_DESTROY_LOCK(rt->gcLock);
739 if (rt->gcDone)
740 JS_DESTROY_CONDVAR(rt->gcDone);
741 if (rt->requestDone)
742 JS_DESTROY_CONDVAR(rt->requestDone);
743 if (rt->rtLock)
744 JS_DESTROY_LOCK(rt->rtLock);
745 if (rt->stateChange)
746 JS_DESTROY_CONDVAR(rt->stateChange);
747 if (rt->setSlotLock)
748 JS_DESTROY_LOCK(rt->setSlotLock);
749 if (rt->setSlotDone)
750 JS_DESTROY_CONDVAR(rt->setSlotDone);
751 if (rt->scopeSharingDone)
752 JS_DESTROY_CONDVAR(rt->scopeSharingDone);
753 #endif
754 js_FinishPropertyTree(rt);
755 free(rt);
756 }
758 JS_PUBLIC_API(void)
759 JS_ShutDown(void)
760 {
761 JS_ArenaShutDown();
762 js_FinishDtoa();
763 js_FreeStringGlobals();
764 #ifdef JS_THREADSAFE
765 js_CleanupLocks();
766 #endif
767 }
769 JS_PUBLIC_API(void *)
770 JS_GetRuntimePrivate(JSRuntime *rt)
771 {
772 return rt->data;
773 }
775 JS_PUBLIC_API(void)
776 JS_SetRuntimePrivate(JSRuntime *rt, void *data)
777 {
778 rt->data = data;
779 }
781 #ifdef JS_THREADSAFE
783 JS_PUBLIC_API(void)
784 JS_BeginRequest(JSContext *cx)
785 {
786 JSRuntime *rt;
788 JS_ASSERT(cx->thread);
789 if (!cx->requestDepth) {
790 /* Wait until the GC is finished. */
791 rt = cx->runtime;
792 JS_LOCK_GC(rt);
794 /* NB: we use cx->thread here, not js_CurrentThreadId(). */
795 if (rt->gcThread != cx->thread) {
796 while (rt->gcLevel > 0)
797 JS_AWAIT_GC_DONE(rt);
798 }
800 /* Indicate that a request is running. */
801 rt->requestCount++;
802 cx->requestDepth = 1;
803 JS_UNLOCK_GC(rt);
804 return;
805 }
806 cx->requestDepth++;
807 }
809 JS_PUBLIC_API(void)
810 JS_EndRequest(JSContext *cx)
811 {
812 JSRuntime *rt;
813 JSScope *scope, **todop;
814 uintN nshares;
816 CHECK_REQUEST(cx);
817 JS_ASSERT(cx->requestDepth > 0);
818 if (cx->requestDepth == 1) {
819 /* Lock before clearing to interlock with ClaimScope, in jslock.c. */
820 rt = cx->runtime;
821 JS_LOCK_GC(rt);
822 cx->requestDepth = 0;
824 /* See whether cx has any single-threaded scopes to start sharing. */
825 todop = &rt->scopeSharingTodo;
826 nshares = 0;
827 while ((scope = *todop) != NO_SCOPE_SHARING_TODO) {
828 if (scope->ownercx != cx) {
829 todop = &scope->u.link;
830 continue;
831 }
832 *todop = scope->u.link;
833 scope->u.link = NULL; /* null u.link for sanity ASAP */
835 /*
836 * If js_DropObjectMap returns null, we held the last ref to scope.
837 * The waiting thread(s) must have been killed, after which the GC
838 * collected the object that held this scope. Unlikely, because it
839 * requires that the GC ran (e.g., from a branch callback) during
840 * this request, but possible.
841 */
842 if (js_DropObjectMap(cx, &scope->map, NULL)) {
843 js_InitLock(&scope->lock);
844 scope->u.count = 0; /* NULL may not pun as 0 */
845 js_FinishSharingScope(rt, scope); /* set ownercx = NULL */
846 nshares++;
847 }
848 }
849 if (nshares)
850 JS_NOTIFY_ALL_CONDVAR(rt->scopeSharingDone);
852 /* Give the GC a chance to run if this was the last request running. */
853 JS_ASSERT(rt->requestCount > 0);
854 rt->requestCount--;
855 if (rt->requestCount == 0)
856 JS_NOTIFY_REQUEST_DONE(rt);
858 JS_UNLOCK_GC(rt);
859 return;
860 }
862 cx->requestDepth--;
863 }
865 /* Yield to pending GC operations, regardless of request depth */
866 JS_PUBLIC_API(void)
867 JS_YieldRequest(JSContext *cx)
868 {
869 JSRuntime *rt;
871 JS_ASSERT(cx->thread);
872 CHECK_REQUEST(cx);
874 rt = cx->runtime;
875 JS_LOCK_GC(rt);
876 JS_ASSERT(rt->requestCount > 0);
877 rt->requestCount--;
878 if (rt->requestCount == 0)
879 JS_NOTIFY_REQUEST_DONE(rt);
880 JS_UNLOCK_GC(rt);
881 /* XXXbe give the GC or another request calling it a chance to run here?
882 Assumes FIFO scheduling */
883 JS_LOCK_GC(rt);
884 rt->requestCount++;
885 JS_UNLOCK_GC(rt);
886 }
888 JS_PUBLIC_API(jsrefcount)
889 JS_SuspendRequest(JSContext *cx)
890 {
891 jsrefcount saveDepth = cx->requestDepth;
893 while (cx->requestDepth)
894 JS_EndRequest(cx);
895 return saveDepth;
896 }
898 JS_PUBLIC_API(void)
899 JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth)
900 {
901 JS_ASSERT(!cx->requestDepth);
902 while (--saveDepth >= 0)
903 JS_BeginRequest(cx);
904 }
906 #endif /* JS_THREADSAFE */
908 JS_PUBLIC_API(void)
909 JS_Lock(JSRuntime *rt)
910 {
911 JS_LOCK_RUNTIME(rt);
912 }
914 JS_PUBLIC_API(void)
915 JS_Unlock(JSRuntime *rt)
916 {
917 JS_UNLOCK_RUNTIME(rt);
918 }
920 JS_PUBLIC_API(JSContext *)
921 JS_NewContext(JSRuntime *rt, size_t stackChunkSize)
922 {
923 return js_NewContext(rt, stackChunkSize);
924 }
926 JS_PUBLIC_API(void)
927 JS_DestroyContext(JSContext *cx)
928 {
929 js_DestroyContext(cx, JS_FORCE_GC);
930 }
932 JS_PUBLIC_API(void)
933 JS_DestroyContextNoGC(JSContext *cx)
934 {
935 js_DestroyContext(cx, JS_NO_GC);
936 }
938 JS_PUBLIC_API(void)
939 JS_DestroyContextMaybeGC(JSContext *cx)
940 {
941 js_DestroyContext(cx, JS_MAYBE_GC);
942 }
944 JS_PUBLIC_API(void *)
945 JS_GetContextPrivate(JSContext *cx)
946 {
947 return cx->data;
948 }
950 JS_PUBLIC_API(void)
951 JS_SetContextPrivate(JSContext *cx, void *data)
952 {
953 cx->data = data;
954 }
956 JS_PUBLIC_API(JSRuntime *)
957 JS_GetRuntime(JSContext *cx)
958 {
959 return cx->runtime;
960 }
962 JS_PUBLIC_API(JSContext *)
963 JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
964 {
965 return js_ContextIterator(rt, JS_TRUE, iterp);
966 }
968 JS_PUBLIC_API(JSVersion)
969 JS_GetVersion(JSContext *cx)
970 {
971 return cx->version;
972 }
974 JS_PUBLIC_API(JSVersion)
975 JS_SetVersion(JSContext *cx, JSVersion version)
976 {
977 JSVersion oldVersion;
979 oldVersion = cx->version;
980 if (version == oldVersion)
981 return oldVersion;
983 cx->version = version;
985 #if !JS_BUG_FALLIBLE_EQOPS
986 if (cx->version == JSVERSION_1_2) {
987 cx->jsop_eq = JSOP_NEW_EQ;
988 cx->jsop_ne = JSOP_NEW_NE;
989 } else {
990 cx->jsop_eq = JSOP_EQ;
991 cx->jsop_ne = JSOP_NE;
992 }
993 #endif /* !JS_BUG_FALLIBLE_EQOPS */
995 return oldVersion;
996 }
998 static struct v2smap {
999 JSVersion version;
1000 const char *string;
1001 } v2smap[] = {
1002 {JSVERSION_1_0, "1.0"},
1003 {JSVERSION_1_1, "1.1"},
1004 {JSVERSION_1_2, "1.2"},
1005 {JSVERSION_1_3, "1.3"},
1006 {JSVERSION_1_4, "1.4"},
1007 {JSVERSION_ECMA_3, "ECMAv3"},
1008 {JSVERSION_1_5, "1.5"},
1009 {JSVERSION_DEFAULT, "default"},
1010 {JSVERSION_UNKNOWN, NULL}, /* must be last, NULL is sentinel */
1011 };
1013 JS_PUBLIC_API(const char *)
1014 JS_VersionToString(JSVersion version)
1015 {
1016 int i;
1018 for (i = 0; v2smap[i].string; i++)
1019 if (v2smap[i].version == version)
1020 return v2smap[i].string;
1021 return "unknown";
1022 }
1024 JS_PUBLIC_API(JSVersion)
1025 JS_StringToVersion(const char *string)
1026 {
1027 int i;
1029 for (i = 0; v2smap[i].string; i++)
1030 if (strcmp(v2smap[i].string, string) == 0)
1031 return v2smap[i].version;
1032 return JSVERSION_UNKNOWN;
1033 }
1035 JS_PUBLIC_API(uint32)
1036 JS_GetOptions(JSContext *cx)
1037 {
1038 return cx->options;
1039 }
1041 JS_PUBLIC_API(uint32)
1042 JS_SetOptions(JSContext *cx, uint32 options)
1043 {
1044 uint32 oldopts = cx->options;
1045 cx->options = options;
1046 return oldopts;
1047 }
1049 JS_PUBLIC_API(uint32)
1050 JS_ToggleOptions(JSContext *cx, uint32 options)
1051 {
1052 uint32 oldopts = cx->options;
1053 cx->options ^= options;
1054 return oldopts;
1055 }
1057 JS_PUBLIC_API(const char *)
1058 JS_GetImplementationVersion(void)
1059 {
1060 return "JavaScript-C 1.5 2004-09-24";
1061 }
1064 JS_PUBLIC_API(JSObject *)
1065 JS_GetGlobalObject(JSContext *cx)
1066 {
1067 return cx->globalObject;
1068 }
1070 JS_PUBLIC_API(void)
1071 JS_SetGlobalObject(JSContext *cx, JSObject *obj)
1072 {
1073 cx->globalObject = obj;
1074 }
1076 static JSObject *
1077 InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
1078 {
1079 JSDHashTable *table;
1080 JSBool resolving;
1081 JSRuntime *rt;
1082 JSResolvingKey key;
1083 JSResolvingEntry *entry;
1084 JSObject *fun_proto, *obj_proto;
1086 /* If cx has no global object, use obj so prototypes can be found. */
1087 if (!cx->globalObject)
1088 cx->globalObject = obj;
1090 /* Record Function and Object in cx->resolvingTable, if we are resolving. */
1091 table = cx->resolvingTable;
1092 resolving = (table && table->entryCount);
1093 if (resolving) {
1094 rt = cx->runtime;
1095 key.obj = obj;
1096 key.id = (jsid) rt->atomState.FunctionAtom;
1097 entry = (JSResolvingEntry *)
1098 JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
1099 if (entry && entry->key.obj && (entry->flags & JSRESFLAG_LOOKUP)) {
1100 /* Already resolving Function, record Object too. */
1101 JS_ASSERT(entry->key.obj == obj);
1102 key.id = (jsid) rt->atomState.ObjectAtom;
1103 entry = (JSResolvingEntry *)
1104 JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
1105 }
1106 if (!entry) {
1107 JS_ReportOutOfMemory(cx);
1108 return NULL;
1109 }
1110 JS_ASSERT(!entry->key.obj && entry->flags == 0);
1111 entry->key = key;
1112 entry->flags = JSRESFLAG_LOOKUP;
1113 }
1115 /* Initialize the function class first so constructors can be made. */
1116 fun_proto = js_InitFunctionClass(cx, obj);
1117 if (!fun_proto)
1118 goto out;
1120 /* Initialize the object class next so Object.prototype works. */
1121 obj_proto = js_InitObjectClass(cx, obj);
1122 if (!obj_proto) {
1123 fun_proto = NULL;
1124 goto out;
1125 }
1127 /* Function.prototype and the global object delegate to Object.prototype. */
1128 OBJ_SET_PROTO(cx, fun_proto, obj_proto);
1129 if (!OBJ_GET_PROTO(cx, obj))
1130 OBJ_SET_PROTO(cx, obj, obj_proto);
1132 out:
1133 /* If resolving, remove the other entry (Object or Function) from table. */
1134 if (resolving)
1135 JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
1136 return fun_proto;
1137 }
1139 JS_PUBLIC_API(JSBool)
1140 JS_InitStandardClasses(JSContext *cx, JSObject *obj)
1141 {
1142 CHECK_REQUEST(cx);
1144 #if JS_HAS_UNDEFINED
1145 {
1146 /* Define a top-level property 'undefined' with the undefined value. */
1147 JSAtom *atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
1148 if (!OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, JSVAL_VOID, NULL, NULL,
1149 JSPROP_PERMANENT, NULL)) {
1150 return JS_FALSE;
1151 }
1152 }
1153 #endif
1155 /* Function and Object require cooperative bootstrapping magic. */
1156 if (!InitFunctionAndObjectClasses(cx, obj))
1157 return JS_FALSE;
1159 /* Initialize the rest of the standard objects and functions. */
1160 return js_InitArrayClass(cx, obj) &&
1161 js_InitBooleanClass(cx, obj) &&
1162 js_InitMathClass(cx, obj) &&
1163 js_InitNumberClass(cx, obj) &&
1164 js_InitStringClass(cx, obj) &&
1165 #if JS_HAS_CALL_OBJECT
1166 js_InitCallClass(cx, obj) &&
1167 #endif
1168 #if JS_HAS_REGEXPS
1169 js_InitRegExpClass(cx, obj) &&
1170 #endif
1171 #if JS_HAS_SCRIPT_OBJECT
1172 js_InitScriptClass(cx, obj) &&
1173 #endif
1174 #if JS_HAS_ERROR_EXCEPTIONS
1175 js_InitExceptionClasses(cx, obj) &&
1176 #endif
1177 #if JS_HAS_FILE_OBJECT
1178 js_InitFileClass(cx, obj, JS_TRUE) &&
1179 #endif
1180 js_InitDateClass(cx, obj);
1181 }
1183 #define ATOM_OFFSET(name) offsetof(JSAtomState, name##Atom)
1184 #define OFFSET_TO_ATOM(rt,off) (*(JSAtom **)((char*)&(rt)->atomState + (off)))
1186 /*
1187 * Table of class initializers and their atom offsets in rt->atomState.
1188 * If you add a "standard" class, remember to update this table.
1189 */
1190 static struct {
1191 JSObjectOp init;
1192 size_t atomOffset;
1193 } standard_class_atoms[] = {
1194 {InitFunctionAndObjectClasses, ATOM_OFFSET(Function)},
1195 {InitFunctionAndObjectClasses, ATOM_OFFSET(Object)},
1196 {js_InitArrayClass, ATOM_OFFSET(Array)},
1197 {js_InitBooleanClass, ATOM_OFFSET(Boolean)},
1198 {js_InitDateClass, ATOM_OFFSET(Date)},
1199 {js_InitMathClass, ATOM_OFFSET(Math)},
1200 {js_InitNumberClass, ATOM_OFFSET(Number)},
1201 {js_InitStringClass, ATOM_OFFSET(String)},
1202 #if JS_HAS_CALL_OBJECT
1203 {js_InitCallClass, ATOM_OFFSET(Call)},
1204 #endif
1205 #if JS_HAS_ERROR_EXCEPTIONS
1206 {js_InitExceptionClasses, ATOM_OFFSET(Error)},
1207 #endif
1208 #if JS_HAS_REGEXPS
1209 {js_InitRegExpClass, ATOM_OFFSET(RegExp)},
1210 #endif
1211 #if JS_HAS_SCRIPT_OBJECT
1212 {js_InitScriptClass, ATOM_OFFSET(Script)},
1213 #endif
1214 {NULL, 0}
1215 };
1217 /*
1218 * Table of top-level function and constant names and their init functions.
1219 * If you add a "standard" global function or property, remember to update
1220 * this table.
1221 */
1222 typedef struct JSStdName {
1223 JSObjectOp init;
1224 size_t atomOffset; /* offset of atom pointer in JSAtomState */
1225 const char *name; /* null if atom is pre-pinned, else name */
1226 } JSStdName;
1228 static JSAtom *
1229 StdNameToAtom(JSContext *cx, JSStdName *stdn)
1230 {
1231 size_t offset;
1232 JSAtom *atom;
1233 const char *name;
1235 offset = stdn->atomOffset;
1236 atom = OFFSET_TO_ATOM(cx->runtime, offset);
1237 if (!atom) {
1238 name = stdn->name;
1239 if (name) {
1240 atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED);
1241 OFFSET_TO_ATOM(cx->runtime, offset) = atom;
1242 }
1243 }
1244 return atom;
1245 }
1247 #define EAGERLY_PINNED_ATOM(name) ATOM_OFFSET(name), NULL
1248 #define LAZILY_PINNED_ATOM(name) ATOM_OFFSET(lazy.name), js_##name##_str
1250 static JSStdName standard_class_names[] = {
1251 /* ECMA requires that eval be a direct property of the global object. */
1252 {js_InitObjectClass, EAGERLY_PINNED_ATOM(eval)},
1254 /* Global properties and functions defined by the Number class. */
1255 {js_InitNumberClass, LAZILY_PINNED_ATOM(NaN)},
1256 {js_InitNumberClass, LAZILY_PINNED_ATOM(Infinity)},
1257 {js_InitNumberClass, LAZILY_PINNED_ATOM(isNaN)},
1258 {js_InitNumberClass, LAZILY_PINNED_ATOM(isFinite)},
1259 {js_InitNumberClass, LAZILY_PINNED_ATOM(parseFloat)},
1260 {js_InitNumberClass, LAZILY_PINNED_ATOM(parseInt)},
1262 /* String global functions. */
1263 {js_InitStringClass, LAZILY_PINNED_ATOM(escape)},
1264 {js_InitStringClass, LAZILY_PINNED_ATOM(unescape)},
1265 {js_InitStringClass, LAZILY_PINNED_ATOM(decodeURI)},
1266 {js_InitStringClass, LAZILY_PINNED_ATOM(encodeURI)},
1267 {js_InitStringClass, LAZILY_PINNED_ATOM(decodeURIComponent)},
1268 {js_InitStringClass, LAZILY_PINNED_ATOM(encodeURIComponent)},
1269 #if JS_HAS_UNEVAL
1270 {js_InitStringClass, LAZILY_PINNED_ATOM(uneval)},
1271 #endif
1273 /* Exception constructors. */
1274 #if JS_HAS_ERROR_EXCEPTIONS
1275 {js_InitExceptionClasses, EAGERLY_PINNED_ATOM(Error)},
1276 {js_InitExceptionClasses, LAZILY_PINNED_ATOM(InternalError)},
1277 {js_InitExceptionClasses, LAZILY_PINNED_ATOM(EvalError)},
1278 {js_InitExceptionClasses, LAZILY_PINNED_ATOM(RangeError)},
1279 {js_InitExceptionClasses, LAZILY_PINNED_ATOM(ReferenceError)},
1280 {js_InitExceptionClasses, LAZILY_PINNED_ATOM(SyntaxError)},
1281 {js_InitExceptionClasses, LAZILY_PINNED_ATOM(TypeError)},
1282 {js_InitExceptionClasses, LAZILY_PINNED_ATOM(URIError)},
1283 #endif
1285 {NULL, 0, NULL}
1286 };
1288 static JSStdName object_prototype_names[] = {
1289 /* Object.prototype properties (global delegates to Object.prototype). */
1290 {js_InitObjectClass, EAGERLY_PINNED_ATOM(proto)},
1291 {js_InitObjectClass, EAGERLY_PINNED_ATOM(parent)},
1292 {js_InitObjectClass, EAGERLY_PINNED_ATOM(count)},
1293 #if JS_HAS_TOSOURCE
1294 {js_InitObjectClass, EAGERLY_PINNED_ATOM(toSource)},
1295 #endif
1296 {js_InitObjectClass, EAGERLY_PINNED_ATOM(toString)},
1297 {js_InitObjectClass, EAGERLY_PINNED_ATOM(toLocaleString)},
1298 {js_InitObjectClass, EAGERLY_PINNED_ATOM(valueOf)},
1299 #if JS_HAS_OBJ_WATCHPOINT
1300 {js_InitObjectClass, LAZILY_PINNED_ATOM(watch)},
1301 {js_InitObjectClass, LAZILY_PINNED_ATOM(unwatch)},
1302 #endif
1303 #if JS_HAS_NEW_OBJ_METHODS
1304 {js_InitObjectClass, LAZILY_PINNED_ATOM(hasOwnProperty)},
1305 {js_InitObjectClass, LAZILY_PINNED_ATOM(isPrototypeOf)},
1306 {js_InitObjectClass, LAZILY_PINNED_ATOM(propertyIsEnumerable)},
1307 #endif
1308 #if JS_HAS_GETTER_SETTER
1309 {js_InitObjectClass, LAZILY_PINNED_ATOM(defineGetter)},
1310 {js_InitObjectClass, LAZILY_PINNED_ATOM(defineSetter)},
1311 {js_InitObjectClass, LAZILY_PINNED_ATOM(lookupGetter)},
1312 {js_InitObjectClass, LAZILY_PINNED_ATOM(lookupSetter)},
1313 #endif
1315 {NULL, 0, NULL}
1316 };
1318 #undef EAGERLY_PINNED_ATOM
1319 #undef LAZILY_PINNED_ATOM
1321 JS_PUBLIC_API(JSBool)
1322 JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id,
1323 JSBool *resolved)
1324 {
1325 JSString *idstr;
1326 JSRuntime *rt;
1327 JSAtom *atom;
1328 JSObjectOp init;
1329 uintN i;
1331 CHECK_REQUEST(cx);
1332 *resolved = JS_FALSE;
1334 if (!JSVAL_IS_STRING(id))
1335 return JS_TRUE;
1336 idstr = JSVAL_TO_STRING(id);
1337 rt = cx->runtime;
1339 #if JS_HAS_UNDEFINED
1340 /* See if we're resolving 'undefined', and define it if so. */
1341 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1342 if (idstr == ATOM_TO_STRING(atom)) {
1343 *resolved = JS_TRUE;
1344 return OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, JSVAL_VOID, NULL, NULL,
1345 JSPROP_PERMANENT, NULL);
1346 }
1347 #endif
1349 /* Try for class constructors/prototypes named by well-known atoms. */
1350 init = NULL;
1351 for (i = 0; standard_class_atoms[i].init; i++) {
1352 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1353 if (idstr == ATOM_TO_STRING(atom)) {
1354 init = standard_class_atoms[i].init;
1355 break;
1356 }
1357 }
1359 if (!init) {
1360 /* Try less frequently used top-level functions and constants. */
1361 for (i = 0; standard_class_names[i].init; i++) {
1362 atom = StdNameToAtom(cx, &standard_class_names[i]);
1363 if (!atom)
1364 return JS_FALSE;
1365 if (idstr == ATOM_TO_STRING(atom)) {
1366 init = standard_class_names[i].init;
1367 break;
1368 }
1369 }
1371 if (!init && !OBJ_GET_PROTO(cx, obj)) {
1372 /*
1373 * Try even less frequently used names delegated from the global
1374 * object to Object.prototype, but only if the Object class hasn't
1375 * yet been initialized.
1376 */
1377 for (i = 0; object_prototype_names[i].init; i++) {
1378 atom = StdNameToAtom(cx, &object_prototype_names[i]);
1379 if (!atom)
1380 return JS_FALSE;
1381 if (idstr == ATOM_TO_STRING(atom)) {
1382 init = standard_class_names[i].init;
1383 break;
1384 }
1385 }
1386 }
1387 }
1389 if (init) {
1390 if (!init(cx, obj))
1391 return JS_FALSE;
1392 *resolved = JS_TRUE;
1393 }
1394 return JS_TRUE;
1395 }
1397 static JSBool
1398 HasOwnProperty(JSContext *cx, JSObject *obj, JSAtom *atom, JSBool *ownp)
1399 {
1400 JSObject *pobj;
1401 JSProperty *prop;
1403 if (!OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &pobj, &prop))
1404 return JS_FALSE;
1405 if (prop)
1406 OBJ_DROP_PROPERTY(cx, pobj, prop);
1407 *ownp = (pobj == obj && prop);
1408 return JS_TRUE;
1409 }
1411 JS_PUBLIC_API(JSBool)
1412 JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
1413 {
1414 JSRuntime *rt;
1415 JSAtom *atom;
1416 JSBool found;
1417 uintN i;
1419 CHECK_REQUEST(cx);
1420 rt = cx->runtime;
1422 #if JS_HAS_UNDEFINED
1423 /* See if we need to bind 'undefined' and define it if so. */
1424 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1425 if (!HasOwnProperty(cx, obj, atom, &found))
1426 return JS_FALSE;
1427 if (!found &&
1428 !OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, JSVAL_VOID, NULL, NULL,
1429 JSPROP_PERMANENT, NULL)) {
1430 return JS_FALSE;
1431 }
1432 #endif
1434 /* Initialize any classes that have not been resolved yet. */
1435 for (i = 0; standard_class_atoms[i].init; i++) {
1436 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1437 if (!HasOwnProperty(cx, obj, atom, &found))
1438 return JS_FALSE;
1439 if (!found && !standard_class_atoms[i].init(cx, obj))
1440 return JS_FALSE;
1441 }
1443 return JS_TRUE;
1444 }
1446 #undef ATOM_OFFSET
1447 #undef OFFSET_TO_ATOM
1449 JS_PUBLIC_API(JSObject *)
1450 JS_GetScopeChain(JSContext *cx)
1451 {
1452 return cx->fp ? cx->fp->scopeChain : NULL;
1453 }
1455 JS_PUBLIC_API(void *)
1456 JS_malloc(JSContext *cx, size_t nbytes)
1457 {
1458 void *p;
1460 JS_ASSERT(nbytes != 0);
1461 if (nbytes == 0)
1462 nbytes = 1;
1463 cx->runtime->gcMallocBytes += nbytes;
1464 p = malloc(nbytes);
1465 if (!p)
1466 JS_ReportOutOfMemory(cx);
1467 return p;
1468 }
1470 JS_PUBLIC_API(void *)
1471 JS_realloc(JSContext *cx, void *p, size_t nbytes)
1472 {
1473 p = realloc(p, nbytes);
1474 if (!p)
1475 JS_ReportOutOfMemory(cx);
1476 return p;
1477 }
1479 JS_PUBLIC_API(void)
1480 JS_free(JSContext *cx, void *p)
1481 {
1482 if (p)
1483 free(p);
1484 }
1486 JS_PUBLIC_API(char *)
1487 JS_strdup(JSContext *cx, const char *s)
1488 {
1489 size_t n;
1490 void *p;
1492 n = strlen(s) + 1;
1493 p = JS_malloc(cx, n);
1494 if (!p)
1495 return NULL;
1496 return (char *)memcpy(p, s, n);
1497 }
1499 JS_PUBLIC_API(jsdouble *)
1500 JS_NewDouble(JSContext *cx, jsdouble d)
1501 {
1502 CHECK_REQUEST(cx);
1503 return js_NewDouble(cx, d);
1504 }
1506 JS_PUBLIC_API(JSBool)
1507 JS_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval)
1508 {
1509 CHECK_REQUEST(cx);
1510 return js_NewDoubleValue(cx, d, rval);
1511 }
1513 JS_PUBLIC_API(JSBool)
1514 JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
1515 {
1516 CHECK_REQUEST(cx);
1517 return js_NewNumberValue(cx, d, rval);
1518 }
1520 #undef JS_AddRoot
1521 JS_PUBLIC_API(JSBool)
1522 JS_AddRoot(JSContext *cx, void *rp)
1523 {
1524 CHECK_REQUEST(cx);
1525 return js_AddRoot(cx, rp, NULL);
1526 }
1528 JS_PUBLIC_API(JSBool)
1529 JS_AddNamedRootRT(JSRuntime *rt, void *rp, const char *name)
1530 {
1531 return js_AddRootRT(rt, rp, name);
1532 }
1534 JS_PUBLIC_API(JSBool)
1535 JS_RemoveRoot(JSContext *cx, void *rp)
1536 {
1537 CHECK_REQUEST(cx);
1538 return js_RemoveRoot(cx->runtime, rp);
1539 }
1541 JS_PUBLIC_API(JSBool)
1542 JS_RemoveRootRT(JSRuntime *rt, void *rp)
1543 {
1544 return js_RemoveRoot(rt, rp);
1545 }
1547 JS_PUBLIC_API(JSBool)
1548 JS_AddNamedRoot(JSContext *cx, void *rp, const char *name)
1549 {
1550 CHECK_REQUEST(cx);
1551 return js_AddRoot(cx, rp, name);
1552 }
1554 JS_PUBLIC_API(void)
1555 JS_ClearNewbornRoots(JSContext *cx)
1556 {
1557 uintN i;
1559 for (i = 0; i < GCX_NTYPES; i++)
1560 cx->newborn[i] = NULL;
1561 cx->lastAtom = NULL;
1562 }
1564 JS_PUBLIC_API(JSBool)
1565 JS_EnterLocalRootScope(JSContext *cx)
1566 {
1567 CHECK_REQUEST(cx);
1568 return js_EnterLocalRootScope(cx);
1569 }
1571 JS_PUBLIC_API(void)
1572 JS_LeaveLocalRootScope(JSContext *cx)
1573 {
1574 CHECK_REQUEST(cx);
1575 js_LeaveLocalRootScope(cx);
1576 }
1578 JS_PUBLIC_API(void)
1579 JS_ForgetLocalRoot(JSContext *cx, void *thing)
1580 {
1581 CHECK_REQUEST(cx);
1582 js_ForgetLocalRoot(cx, (jsval) thing);
1583 }
1585 #include "jshash.h" /* Added by JSIFY */
1587 #ifdef DEBUG
1589 typedef struct NamedRootDumpArgs {
1590 void (*dump)(const char *name, void *rp, void *data);
1591 void *data;
1592 } NamedRootDumpArgs;
1594 JS_STATIC_DLL_CALLBACK(JSDHashOperator)
1595 js_named_root_dumper(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
1596 void *arg)
1597 {
1598 NamedRootDumpArgs *args = (NamedRootDumpArgs *) arg;
1599 JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
1601 if (rhe->name)
1602 args->dump(rhe->name, rhe->root, args->data);
1603 return JS_DHASH_NEXT;
1604 }
1606 JS_PUBLIC_API(void)
1607 JS_DumpNamedRoots(JSRuntime *rt,
1608 void (*dump)(const char *name, void *rp, void *data),
1609 void *data)
1610 {
1611 NamedRootDumpArgs args;
1613 args.dump = dump;
1614 args.data = data;
1615 JS_DHashTableEnumerate(&rt->gcRootsHash, js_named_root_dumper, &args);
1616 }
1618 #endif /* DEBUG */
1620 typedef struct GCRootMapArgs {
1621 JSGCRootMapFun map;
1622 void *data;
1623 } GCRootMapArgs;
1625 JS_STATIC_DLL_CALLBACK(JSDHashOperator)
1626 js_gcroot_mapper(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
1627 void *arg)
1628 {
1629 GCRootMapArgs *args = (GCRootMapArgs *) arg;
1630 JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
1631 intN mapflags;
1632 JSDHashOperator op;
1634 mapflags = args->map(rhe->root, rhe->name, args->data);
1636 #if JS_MAP_GCROOT_NEXT == JS_DHASH_NEXT && \
1637 JS_MAP_GCROOT_STOP == JS_DHASH_STOP && \
1638 JS_MAP_GCROOT_REMOVE == JS_DHASH_REMOVE
1639 op = (JSDHashOperator)mapflags;
1640 #else
1641 op = JS_DHASH_NEXT;
1642 if (mapflags & JS_MAP_GCROOT_STOP)
1643 op |= JS_DHASH_STOP;
1644 if (mapflags & JS_MAP_GCROOT_REMOVE)
1645 op |= JS_DHASH_REMOVE;
1646 #endif
1648 return op;
1649 }
1651 JS_PUBLIC_API(uint32)
1652 JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
1653 {
1654 GCRootMapArgs args;
1655 uint32 rv;
1657 args.map = map;
1658 args.data = data;
1659 JS_LOCK_GC(rt);
1660 rv = JS_DHashTableEnumerate(&rt->gcRootsHash, js_gcroot_mapper, &args);
1661 JS_UNLOCK_GC(rt);
1662 return rv;
1663 }
1665 JS_PUBLIC_API(JSBool)
1666 JS_LockGCThing(JSContext *cx, void *thing)
1667 {
1668 JSBool ok;
1670 CHECK_REQUEST(cx);
1671 ok = js_LockGCThing(cx, thing);
1672 if (!ok)
1673 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_LOCK);
1674 return ok;
1675 }
1677 JS_PUBLIC_API(JSBool)
1678 JS_LockGCThingRT(JSRuntime *rt, void *thing)
1679 {
1680 return js_LockGCThingRT(rt, thing);
1681 }
1683 JS_PUBLIC_API(JSBool)
1684 JS_UnlockGCThing(JSContext *cx, void *thing)
1685 {
1686 JSBool ok;
1688 CHECK_REQUEST(cx);
1689 ok = js_UnlockGCThingRT(cx->runtime, thing);
1690 if (!ok)
1691 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_UNLOCK);
1692 return ok;
1693 }
1695 JS_PUBLIC_API(JSBool)
1696 JS_UnlockGCThingRT(JSRuntime *rt, void *thing)
1697 {
1698 return js_UnlockGCThingRT(rt, thing);
1699 }
1701 JS_PUBLIC_API(void)
1702 JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg)
1703 {
1704 JS_ASSERT(cx->runtime->gcLevel > 0);
1705 #ifdef JS_THREADSAFE
1706 JS_ASSERT(cx->runtime->gcThread == js_CurrentThreadId());
1707 #endif
1709 GC_MARK(cx, thing, name, arg);
1710 }
1712 JS_PUBLIC_API(void)
1713 JS_GC(JSContext *cx)
1714 {
1715 /* Don't nuke active arenas if executing or compiling. */
1716 if (cx->stackPool.current == &cx->stackPool.first)
1717 JS_FinishArenaPool(&cx->stackPool);
1718 if (cx->tempPool.current == &cx->tempPool.first)
1719 JS_FinishArenaPool(&cx->tempPool);
1720 js_ForceGC(cx, 0);
1721 }
1723 JS_PUBLIC_API(void)
1724 JS_MaybeGC(JSContext *cx)
1725 {
1726 JSRuntime *rt;
1727 uint32 bytes, lastBytes;
1729 rt = cx->runtime;
1730 bytes = rt->gcBytes;
1731 lastBytes = rt->gcLastBytes;
1732 if ((bytes > 8192 && bytes > lastBytes + lastBytes / 2) ||
1733 rt->gcMallocBytes > rt->gcMaxBytes) {
1734 /*
1735 * Run the GC if we have half again as many bytes of GC-things as
1736 * the last time we GC'd, or if we have malloc'd more bytes through
1737 * JS_malloc than we were told to allocate by JS_NewRuntime.
1738 */
1739 JS_GC(cx);
1740 }
1741 }
1743 JS_PUBLIC_API(JSGCCallback)
1744 JS_SetGCCallback(JSContext *cx, JSGCCallback cb)
1745 {
1746 return JS_SetGCCallbackRT(cx->runtime, cb);
1747 }
1749 JS_PUBLIC_API(JSGCCallback)
1750 JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb)
1751 {
1752 JSGCCallback oldcb;
1754 oldcb = rt->gcCallback;
1755 rt->gcCallback = cb;
1756 return oldcb;
1757 }
1759 JS_PUBLIC_API(JSBool)
1760 JS_IsAboutToBeFinalized(JSContext *cx, void *thing)
1761 {
1762 JS_ASSERT(thing);
1763 return js_IsAboutToBeFinalized(cx, thing);
1764 }
1766 JS_PUBLIC_API(intN)
1767 JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer)
1768 {
1769 return js_ChangeExternalStringFinalizer(NULL, finalizer);
1770 }
1772 JS_PUBLIC_API(intN)
1773 JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer)
1774 {
1775 return js_ChangeExternalStringFinalizer(finalizer, NULL);
1776 }
1778 JS_PUBLIC_API(JSString *)
1779 JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
1780 {
1781 JSString *str;
1783 CHECK_REQUEST(cx);
1784 JS_ASSERT(GCX_EXTERNAL_STRING <= type && type < (intN) GCX_NTYPES);
1786 str = (JSString *) js_AllocGCThing(cx, (uintN) type);
1787 if (!str)
1788 return NULL;
1789 str->length = length;
1790 str->chars = chars;
1791 return str;
1792 }
1794 JS_PUBLIC_API(intN)
1795 JS_GetExternalStringGCType(JSRuntime *rt, JSString *str)
1796 {
1797 uint8 type = (uint8) (*js_GetGCThingFlags(str) & GCF_TYPEMASK);
1799 if (type >= GCX_EXTERNAL_STRING)
1800 return (intN)type;
1801 JS_ASSERT(type == GCX_STRING || type == GCX_MUTABLE_STRING);
1802 return -1;
1803 }
1805 #ifdef DEBUG
1806 /* FIXME: 242518 static */ void
1807 CheckStackGrowthDirection(int *dummy1addr, jsuword limitAddr)
1808 {
1809 int dummy2;
1811 #if JS_STACK_GROWTH_DIRECTION > 0
1812 JS_ASSERT(dummy1addr < &dummy2);
1813 JS_ASSERT((jsuword)&dummy2 < limitAddr);
1814 #else
1815 /* Stack grows downward, the common case on modern architectures. */
1816 JS_ASSERT(&dummy2 < dummy1addr);
1817 JS_ASSERT(limitAddr < (jsuword)&dummy2);
1818 #endif
1819 }
1820 #endif
1822 JS_PUBLIC_API(void)
1823 JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr)
1824 {
1825 #ifdef DEBUG
1826 int dummy1;
1828 CheckStackGrowthDirection(&dummy1, limitAddr);
1829 #endif
1831 #if JS_STACK_GROWTH_DIRECTION > 0
1832 if (limitAddr == 0)
1833 limitAddr = (jsuword)-1;
1834 #endif
1835 cx->stackLimit = limitAddr;
1836 }
1838 /************************************************************************/
1840 JS_PUBLIC_API(void)
1841 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
1842 {
1843 JS_free(cx, ida);
1844 }
1846 JS_PUBLIC_API(JSBool)
1847 JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
1848 {
1849 JSAtom *atom;
1851 CHECK_REQUEST(cx);
1852 if (JSVAL_IS_INT(v)) {
1853 *idp = v;
1854 } else {
1855 atom = js_ValueToStringAtom(cx, v);
1856 if (!atom)
1857 return JS_FALSE;
1858 *idp = (jsid)atom;
1859 }
1860 return JS_TRUE;
1861 }
1863 JS_PUBLIC_API(JSBool)
1864 JS_IdToValue(JSContext *cx, jsid id, jsval *vp)
1865 {
1866 CHECK_REQUEST(cx);
1867 *vp = ID_TO_VALUE(id);
1868 return JS_TRUE;
1869 }
1871 JS_PUBLIC_API(JSBool)
1872 JS_PropertyStub(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
1873 {
1874 return JS_TRUE;
1875 }
1877 JS_PUBLIC_API(JSBool)
1878 JS_EnumerateStub(JSContext *cx, JSObject *obj)
1879 {
1880 return JS_TRUE;
1881 }
1883 JS_PUBLIC_API(JSBool)
1884 JS_ResolveStub(JSContext *cx, JSObject *obj, jsval id)
1885 {
1886 return JS_TRUE;
1887 }
1889 JS_PUBLIC_API(JSBool)
1890 JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
1891 {
1892 #if JS_BUG_EAGER_TOSTRING
1893 if (type == JSTYPE_STRING)
1894 return JS_TRUE;
1895 #endif
1896 return js_TryValueOf(cx, obj, type, vp);
1897 }
1899 JS_PUBLIC_API(void)
1900 JS_FinalizeStub(JSContext *cx, JSObject *obj)
1901 {
1902 }
1904 JS_PUBLIC_API(JSObject *)
1905 JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
1906 JSClass *clasp, JSNative constructor, uintN nargs,
1907 JSPropertySpec *ps, JSFunctionSpec *fs,
1908 JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
1909 {
1910 JSAtom *atom;
1911 JSObject *proto, *ctor;
1912 JSBool named;
1913 JSFunction *fun;
1914 jsval junk;
1916 CHECK_REQUEST(cx);
1917 atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0);
1918 if (!atom)
1919 return NULL;
1921 /* Create a prototype object for this class. */
1922 proto = js_NewObject(cx, clasp, parent_proto, obj);
1923 if (!proto)
1924 return NULL;
1926 if (!constructor) {
1927 /* Lacking a constructor, name the prototype (e.g., Math). */
1928 named = OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, OBJECT_TO_JSVAL(proto),
1929 NULL, NULL, 0, NULL);
1930 if (!named)
1931 goto bad;
1932 ctor = proto;
1933 } else {
1934 /* Define the constructor function in obj's scope. */
1935 fun = js_DefineFunction(cx, obj, atom, constructor, nargs, 0);
1936 named = (fun != NULL);
1937 if (!fun)
1938 goto bad;
1940 /*
1941 * Remember the class this function is a constructor for so that
1942 * we know to create an object of this class when we call the
1943 * constructor.
1944 */
1945 fun->clasp = clasp;
1947 /* Connect constructor and prototype by named properties. */
1948 ctor = fun->object;
1949 if (!js_SetClassPrototype(cx, ctor, proto,
1950 JSPROP_READONLY | JSPROP_PERMANENT)) {
1951 goto bad;
1952 }
1954 /* Bootstrap Function.prototype (see also JS_InitStandardClasses). */
1955 if (OBJ_GET_CLASS(cx, ctor) == clasp) {
1956 /* XXXMLM - this fails in framesets that are writing over
1957 * themselves!
1958 * JS_ASSERT(!OBJ_GET_PROTO(cx, ctor));
1959 */
1960 OBJ_SET_PROTO(cx, ctor, proto);
1961 }
1962 }
1964 /* Add properties and methods to the prototype and the constructor. */
1965 if ((ps && !JS_DefineProperties(cx, proto, ps)) ||
1966 (fs && !JS_DefineFunctions(cx, proto, fs)) ||
1967 (static_ps && !JS_DefineProperties(cx, ctor, static_ps)) ||
1968 (static_fs && !JS_DefineFunctions(cx, ctor, static_fs))) {
1969 goto bad;
1970 }
1971 return proto;
1973 bad:
1974 if (named)
1975 (void) OBJ_DELETE_PROPERTY(cx, obj, (jsid)atom, &junk);
1976 cx->newborn[GCX_OBJECT] = NULL;
1977 return NULL;
1978 }
1980 #ifdef JS_THREADSAFE
1981 JS_PUBLIC_API(JSClass *)
1982 JS_GetClass(JSContext *cx, JSObject *obj)
1983 {
1984 return (JSClass *)
1985 JSVAL_TO_PRIVATE(GC_AWARE_GET_SLOT(cx, obj, JSSLOT_CLASS));
1986 }
1987 #else
1988 JS_PUBLIC_API(JSClass *)
1989 JS_GetClass(JSObject *obj)
1990 {
1991 return LOCKED_OBJ_GET_CLASS(obj);
1992 }
1993 #endif
1995 JS_PUBLIC_API(JSBool)
1996 JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
1997 {
1998 JSFunction *fun;
2000 CHECK_REQUEST(cx);
2001 if (OBJ_GET_CLASS(cx, obj) == clasp)
2002 return JS_TRUE;
2003 if (argv) {
2004 fun = js_ValueToFunction(cx, &argv[-2], 0);
2005 if (fun) {
2006 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2007 JSMSG_INCOMPATIBLE_PROTO,
2008 clasp->name, JS_GetFunctionName(fun),
2009 OBJ_GET_CLASS(cx, obj)->name);
2010 }
2011 }
2012 return JS_FALSE;
2013 }
2015 JS_PUBLIC_API(void *)
2016 JS_GetPrivate(JSContext *cx, JSObject *obj)
2017 {
2018 jsval v;
2020 JS_ASSERT(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE);
2021 v = GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
2022 if (!JSVAL_IS_INT(v))
2023 return NULL;
2024 return JSVAL_TO_PRIVATE(v);
2025 }
2027 JS_PUBLIC_API(JSBool)
2028 JS_SetPrivate(JSContext *cx, JSObject *obj, void *data)
2029 {
2030 JS_ASSERT(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE);
2031 OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(data));
2032 return JS_TRUE;
2033 }
2035 JS_PUBLIC_API(void *)
2036 JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp,
2037 jsval *argv)
2038 {
2039 if (!JS_InstanceOf(cx, obj, clasp, argv))
2040 return NULL;
2041 return JS_GetPrivate(cx, obj);
2042 }
2044 JS_PUBLIC_API(JSObject *)
2045 JS_GetPrototype(JSContext *cx, JSObject *obj)
2046 {
2047 JSObject *proto;
2049 CHECK_REQUEST(cx);
2050 proto = JSVAL_TO_OBJECT(GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PROTO));
2052 /* Beware ref to dead object (we may be called from obj's finalizer). */
2053 return proto && proto->map ? proto : NULL;
2054 }
2056 JS_PUBLIC_API(JSBool)
2057 JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto)
2058 {
2059 CHECK_REQUEST(cx);
2060 if (obj->map->ops->setProto)
2061 return obj->map->ops->setProto(cx, obj, JSSLOT_PROTO, proto);
2062 OBJ_SET_SLOT(cx, obj, JSSLOT_PROTO, OBJECT_TO_JSVAL(proto));
2063 return JS_TRUE;
2064 }
2066 JS_PUBLIC_API(JSObject *)
2067 JS_GetParent(JSContext *cx, JSObject *obj)
2068 {
2069 JSObject *parent;
2071 parent = JSVAL_TO_OBJECT(GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PARENT));
2073 /* Beware ref to dead object (we may be called from obj's finalizer). */
2074 return parent && parent->map ? parent : NULL;
2075 }
2077 JS_PUBLIC_API(JSBool)
2078 JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
2079 {
2080 CHECK_REQUEST(cx);
2081 if (obj->map->ops->setParent)
2082 return obj->map->ops->setParent(cx, obj, JSSLOT_PARENT, parent);
2083 OBJ_SET_SLOT(cx, obj, JSSLOT_PARENT, OBJECT_TO_JSVAL(parent));
2084 return JS_TRUE;
2085 }
2087 JS_PUBLIC_API(JSObject *)
2088 JS_GetConstructor(JSContext *cx, JSObject *proto)
2089 {
2090 jsval cval;
2092 CHECK_REQUEST(cx);
2093 if (!OBJ_GET_PROPERTY(cx, proto,
2094 (jsid)cx->runtime->atomState.constructorAtom,
2095 &cval)) {
2096 return NULL;
2097 }
2098 if (!JSVAL_IS_FUNCTION(cx, cval)) {
2099 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR,
2100 OBJ_GET_CLASS(cx, proto)->name);
2101 return NULL;
2102 }
2103 return JSVAL_TO_OBJECT(cval);
2104 }
2106 JS_PUBLIC_API(JSBool)
2107 JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
2108 {
2109 JS_ASSERT(((jsid)obj & JSVAL_TAGMASK) == 0);
2110 *idp = (jsid) obj | JSVAL_INT;
2111 return JS_TRUE;
2112 }
2114 JS_PUBLIC_API(JSObject *)
2115 JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
2116 {
2117 CHECK_REQUEST(cx);
2118 if (!clasp)
2119 clasp = &js_ObjectClass; /* default class is Object */
2120 return js_NewObject(cx, clasp, proto, parent);
2121 }
2123 JS_PUBLIC_API(JSBool)
2124 JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep)
2125 {
2126 JSScope *scope;
2127 JSIdArray *ida;
2128 uint32 nslots;
2129 jsval v, *vp, *end;
2131 if (!OBJ_IS_NATIVE(obj)) {
2132 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2133 JSMSG_CANT_SEAL_OBJECT,
2134 OBJ_GET_CLASS(cx, obj)->name);
2135 return JS_FALSE;
2136 }
2138 scope = OBJ_SCOPE(obj);
2140 #if defined JS_THREADSAFE && defined DEBUG
2141 /* Insist on scope being used exclusively by cx's thread. */
2142 if (scope->ownercx != cx) {
2143 JS_LOCK_OBJ(cx, obj);
2144 JS_ASSERT(OBJ_SCOPE(obj) == scope);
2145 JS_ASSERT(scope->ownercx == cx);
2146 JS_UNLOCK_SCOPE(cx, scope);
2147 }
2148 #endif
2150 /* Nothing to do if obj's scope is already sealed. */
2151 if (SCOPE_IS_SEALED(scope))
2152 return JS_TRUE;
2154 /* XXX Enumerate lazy properties now, as they can't be added later. */
2155 ida = JS_Enumerate(cx, obj);
2156 if (!ida)
2157 return JS_FALSE;
2158 JS_DestroyIdArray(cx, ida);
2160 /* Ensure that obj has its own, mutable scope, and seal that scope. */
2161 JS_LOCK_OBJ(cx, obj);
2162 scope = js_GetMutableScope(cx, obj);
2163 if (scope)
2164 SCOPE_SET_SEALED(scope);
2165 JS_UNLOCK_SCOPE(cx, scope);
2166 if (!scope)
2167 return JS_FALSE;
2169 /* If we are not sealing an entire object graph, we're done. */
2170 if (!deep)
2171 return JS_TRUE;
2173 /* Walk obj->slots and if any value is a non-null object, seal it. */
2174 nslots = JS_MIN(scope->map.freeslot, scope->map.nslots);
2175 for (vp = obj->slots, end = vp + nslots; vp < end; vp++) {
2176 v = *vp;
2177 if (JSVAL_IS_PRIMITIVE(v))
2178 continue;
2179 if (!JS_SealObject(cx, JSVAL_TO_OBJECT(v), deep))
2180 return JS_FALSE;
2181 }
2182 return JS_TRUE;
2183 }
2185 JS_PUBLIC_API(JSObject *)
2186 JS_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
2187 JSObject *parent)
2188 {
2189 CHECK_REQUEST(cx);
2190 if (!clasp)
2191 clasp = &js_ObjectClass; /* default class is Object */
2192 return js_ConstructObject(cx, clasp, proto, parent, 0, NULL);
2193 }
2195 JS_PUBLIC_API(JSObject *)
2196 JS_ConstructObjectWithArguments(JSContext *cx, JSClass *clasp, JSObject *proto,
2197 JSObject *parent, uintN argc, jsval *argv)
2198 {
2199 CHECK_REQUEST(cx);
2200 if (!clasp)
2201 clasp = &js_ObjectClass; /* default class is Object */
2202 return js_ConstructObject(cx, clasp, proto, parent, argc, argv);
2203 }
2205 static JSBool
2206 DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
2207 JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
2208 uintN flags, intN tinyid)
2209 {
2210 jsid id;
2211 JSAtom *atom;
2213 if (attrs & JSPROP_INDEX) {
2214 id = INT_TO_JSVAL((jsint)name);
2215 atom = NULL;
2216 attrs &= ~JSPROP_INDEX;
2217 } else {
2218 atom = js_Atomize(cx, name, strlen(name), 0);
2219 if (!atom)
2220 return JS_FALSE;
2221 id = (jsid)atom;
2222 }
2223 if (flags != 0 && OBJ_IS_NATIVE(obj)) {
2224 return js_DefineNativeProperty(cx, obj, id, value, getter, setter,
2225 attrs, flags, tinyid, NULL);
2226 }
2227 return OBJ_DEFINE_PROPERTY(cx, obj, id, value, getter, setter, attrs,
2228 NULL);
2229 }
2231 #define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n))
2233 static JSBool
2234 DefineUCProperty(JSContext *cx, JSObject *obj,
2235 const jschar *name, size_t namelen, jsval value,
2236 JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
2237 uintN flags, intN tinyid)
2238 {
2239 JSAtom *atom;
2241 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
2242 if (!atom)
2243 return JS_FALSE;
2244 if (flags != 0 && OBJ_IS_NATIVE(obj)) {
2245 return js_DefineNativeProperty(cx, obj, (jsid)atom, value,
2246 getter, setter, attrs, flags, tinyid,
2247 NULL);
2248 }
2249 return OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, value, getter, setter,
2250 attrs, NULL);
2251 }
2253 JS_PUBLIC_API(JSObject *)
2254 JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *clasp,
2255 JSObject *proto, uintN attrs)
2256 {
2257 JSObject *nobj;
2259 CHECK_REQUEST(cx);
2260 if (!clasp)
2261 clasp = &js_ObjectClass; /* default class is Object */
2262 nobj = js_NewObject(cx, clasp, proto, obj);
2263 if (!nobj)
2264 return NULL;
2265 if (!DefineProperty(cx, obj, name, OBJECT_TO_JSVAL(nobj), NULL, NULL, attrs,
2266 0, 0)) {
2267 cx->newborn[GCX_OBJECT] = NULL;
2268 return NULL;
2269 }
2270 return nobj;
2271 }
2273 JS_PUBLIC_API(JSBool)
2274 JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds)
2275 {
2276 JSBool ok;
2277 jsval value;
2278 uintN flags;
2280 CHECK_REQUEST(cx);
2281 for (ok = JS_TRUE; cds->name; cds++) {
2282 ok = js_NewNumberValue(cx, cds->dval, &value);
2283 if (!ok)
2284 break;
2285 flags = cds->flags;
2286 if (!flags)
2287 flags = JSPROP_READONLY | JSPROP_PERMANENT;
2288 ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, flags, 0, 0);
2289 if (!ok)
2290 break;
2291 }
2292 return ok;
2293 }
2295 JS_PUBLIC_API(JSBool)
2296 JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps)
2297 {
2298 JSBool ok;
2300 CHECK_REQUEST(cx);
2301 for (ok = JS_TRUE; ps->name; ps++) {
2302 ok = DefineProperty(cx, obj, ps->name, JSVAL_VOID,
2303 ps->getter, ps->setter, ps->flags,
2304 SPROP_HAS_SHORTID, ps->tinyid);
2305 if (!ok)
2306 break;
2307 }
2308 return ok;
2309 }
2311 JS_PUBLIC_API(JSBool)
2312 JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
2313 JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
2314 {
2315 CHECK_REQUEST(cx);
2316 return DefineProperty(cx, obj, name, value, getter, setter, attrs, 0, 0);
2317 }
2319 JS_PUBLIC_API(JSBool)
2320 JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name,
2321 int8 tinyid, jsval value,
2322 JSPropertyOp getter, JSPropertyOp setter,
2323 uintN attrs)
2324 {
2325 CHECK_REQUEST(cx);
2326 return DefineProperty(cx, obj, name, value, getter, setter, attrs,
2327 SPROP_HAS_SHORTID, tinyid);
2328 }
2330 static JSBool
2331 LookupProperty(JSContext *cx, JSObject *obj, const char *name, JSObject **objp,
2332 JSProperty **propp)
2333 {
2334 JSAtom *atom;
2336 atom = js_Atomize(cx, name, strlen(name), 0);
2337 if (!atom)
2338 return JS_FALSE;
2339 return OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, objp, propp);
2340 }
2342 static JSBool
2343 LookupUCProperty(JSContext *cx, JSObject *obj,
2344 const jschar *name, size_t namelen,
2345 JSObject **objp, JSProperty **propp)
2346 {
2347 JSAtom *atom;
2349 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
2350 if (!atom)
2351 return JS_FALSE;
2352 return OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, objp, propp);
2353 }
2355 JS_PUBLIC_API(JSBool)
2356 JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name,
2357 const char *alias)
2358 {
2359 JSObject *obj2;
2360 JSProperty *prop;
2361 JSAtom *atom;
2362 JSBool ok;
2363 JSScopeProperty *sprop;
2365 CHECK_REQUEST(cx);
2366 if (!LookupProperty(cx, obj, name, &obj2, &prop))
2367 return JS_FALSE;
2368 if (!prop) {
2369 js_ReportIsNotDefined(cx, name);
2370 return JS_FALSE;
2371 }
2372 if (obj2 != obj || !OBJ_IS_NATIVE(obj)) {
2373 OBJ_DROP_PROPERTY(cx, obj2, prop);
2374 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
2375 alias, name, OBJ_GET_CLASS(cx, obj2)->name);
2376 return JS_FALSE;
2377 }
2378 atom = js_Atomize(cx, alias, strlen(alias), 0);
2379 if (!atom) {
2380 ok = JS_FALSE;
2381 } else {
2382 sprop = (JSScopeProperty *)prop;
2383 ok = (js_AddNativeProperty(cx, obj, (jsid)atom,
2384 sprop->getter, sprop->setter, sprop->slot,
2385 sprop->attrs, sprop->flags | SPROP_IS_ALIAS,
2386 sprop->shortid)
2387 != NULL);
2388 }
2389 OBJ_DROP_PROPERTY(cx, obj, prop);
2390 return ok;
2391 }
2393 static jsval
2394 LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, JSProperty *prop)
2395 {
2396 JSScopeProperty *sprop;
2397 jsval rval;
2399 if (!prop) {
2400 /* XXX bad API: no way to tell "not defined" from "void value" */
2401 return JSVAL_VOID;
2402 }
2403 if (OBJ_IS_NATIVE(obj2)) {
2404 /* Peek at the native property's slot value, without doing a Get. */
2405 sprop = (JSScopeProperty *)prop;
2406 rval = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj2))
2407 ? LOCKED_OBJ_GET_SLOT(obj2, sprop->slot)
2408 : JSVAL_TRUE;
2409 } else {
2410 /* XXX bad API: no way to return "defined but value unknown" */
2411 rval = JSVAL_TRUE;
2412 }
2413 OBJ_DROP_PROPERTY(cx, obj2, prop);
2414 return rval;
2415 }
2417 static JSBool
2418 GetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom,
2419 uintN *attrsp, JSBool *foundp)
2420 {
2421 JSObject *obj2;
2422 JSProperty *prop;
2423 JSBool ok;
2425 if (!atom)
2426 return JS_FALSE;
2427 if (!OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &obj2, &prop))
2428 return JS_FALSE;
2429 if (!prop || obj != obj2) {
2430 *foundp = JS_FALSE;
2431 if (prop)
2432 OBJ_DROP_PROPERTY(cx, obj2, prop);
2433 return JS_TRUE;
2434 }
2436 *foundp = JS_TRUE;
2437 ok = OBJ_GET_ATTRIBUTES(cx, obj, (jsid)atom, prop, attrsp);
2438 OBJ_DROP_PROPERTY(cx, obj, prop);
2439 return ok;
2440 }
2442 static JSBool
2443 SetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom,
2444 uintN attrs, JSBool *foundp)
2445 {
2446 JSObject *obj2;
2447 JSProperty *prop;
2448 JSBool ok;
2450 if (!atom)
2451 return JS_FALSE;
2452 if (!OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &obj2, &prop))
2453 return JS_FALSE;
2454 if (!prop || obj != obj2) {
2455 *foundp = JS_FALSE;
2456 if (prop)
2457 OBJ_DROP_PROPERTY(cx, obj2, prop);
2458 return JS_TRUE;
2459 }
2461 *foundp = JS_TRUE;
2462 ok = OBJ_SET_ATTRIBUTES(cx, obj, (jsid)atom, prop, &attrs);
2463 OBJ_DROP_PROPERTY(cx, obj, prop);
2464 return ok;
2465 }
2468 JS_PUBLIC_API(JSBool)
2469 JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
2470 uintN *attrsp, JSBool *foundp)
2471 {
2472 CHECK_REQUEST(cx);
2473 return GetPropertyAttributes(cx, obj,
2474 js_Atomize(cx, name, strlen(name), 0),
2475 attrsp, foundp);
2476 }
2478 JS_PUBLIC_API(JSBool)
2479 JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
2480 uintN attrs, JSBool *foundp)
2481 {
2482 CHECK_REQUEST(cx);
2483 return SetPropertyAttributes(cx, obj,
2484 js_Atomize(cx, name, strlen(name), 0),
2485 attrs, foundp);
2486 }
2488 JS_PUBLIC_API(JSBool)
2489 JS_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
2490 {
2491 JSBool ok;
2492 JSObject *obj2;
2493 JSProperty *prop;
2495 CHECK_REQUEST(cx);
2496 ok = LookupProperty(cx, obj, name, &obj2, &prop);
2497 if (ok) {
2498 *foundp = (prop != NULL);
2499 if (prop)
2500 OBJ_DROP_PROPERTY(cx, obj2, prop);
2501 }
2502 return ok;
2503 }
2505 JS_PUBLIC_API(JSBool)
2506 JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
2507 {
2508 JSBool ok;
2509 JSObject *obj2;
2510 JSProperty *prop;
2512 CHECK_REQUEST(cx);
2513 ok = LookupProperty(cx, obj, name, &obj2, &prop);
2514 if (ok)
2515 *vp = LookupResult(cx, obj, obj2, prop);
2516 return ok;
2517 }
2519 JS_PUBLIC_API(JSBool)
2520 JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name,
2521 uintN flags, jsval *vp)
2522 {
2523 JSAtom *atom;
2524 JSBool ok;
2525 JSObject *obj2;
2526 JSProperty *prop;
2528 CHECK_REQUEST(cx);
2529 atom = js_Atomize(cx, name, strlen(name), 0);
2530 if (!atom)
2531 return JS_FALSE;
2532 ok = OBJ_IS_NATIVE(obj)
2533 ? js_LookupPropertyWithFlags(cx, obj, (jsid)atom, flags, &obj2, &prop
2534 #if defined JS_THREADSAFE && defined DEBUG
2535 , __FILE__, __LINE__
2536 #endif
2537 )
2538 : OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &obj2, &prop);
2539 if (ok)
2540 *vp = LookupResult(cx, obj, obj2, prop);
2541 return ok;
2542 }
2544 JS_PUBLIC_API(JSBool)
2545 JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
2546 {
2547 JSAtom *atom;
2549 CHECK_REQUEST(cx);
2550 atom = js_Atomize(cx, name, strlen(name), 0);
2551 if (!atom)
2552 return JS_FALSE;
2553 return OBJ_GET_PROPERTY(cx, obj, (jsid)atom, vp);
2554 }
2556 JS_PUBLIC_API(JSBool)
2557 JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
2558 {
2559 JSAtom *atom;
2561 CHECK_REQUEST(cx);
2562 atom = js_Atomize(cx, name, strlen(name), 0);
2563 if (!atom)
2564 return JS_FALSE;
2565 return OBJ_SET_PROPERTY(cx, obj, (jsid)atom, vp);
2566 }
2568 JS_PUBLIC_API(JSBool)
2569 JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name)
2570 {
2571 jsval junk;
2573 CHECK_REQUEST(cx);
2574 return JS_DeleteProperty2(cx, obj, name, &junk);
2575 }
2577 JS_PUBLIC_API(JSBool)
2578 JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name,
2579 jsval *rval)
2580 {
2581 JSAtom *atom;
2583 CHECK_REQUEST(cx);
2584 atom = js_Atomize(cx, name, strlen(name), 0);
2585 if (!atom)
2586 return JS_FALSE;
2587 return OBJ_DELETE_PROPERTY(cx, obj, (jsid)atom, rval);
2588 }
2590 JS_PUBLIC_API(JSBool)
2591 JS_DefineUCProperty(JSContext *cx, JSObject *obj,
2592 const jschar *name, size_t namelen, jsval value,
2593 JSPropertyOp getter, JSPropertyOp setter,
2594 uintN attrs)
2595 {
2596 CHECK_REQUEST(cx);
2597 return DefineUCProperty(cx, obj, name, namelen, value, getter, setter,
2598 attrs, 0, 0);
2599 }
2601 JS_PUBLIC_API(JSBool)
2602 JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj,
2603 const jschar *name, size_t namelen,
2604 uintN *attrsp, JSBool *foundp)
2605 {
2606 CHECK_REQUEST(cx);
2607 return GetPropertyAttributes(cx, obj,
2608 js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
2609 attrsp, foundp);
2610 }
2612 JS_PUBLIC_API(JSBool)
2613 JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj,
2614 const jschar *name, size_t namelen,
2615 uintN attrs, JSBool *foundp)
2616 {
2617 CHECK_REQUEST(cx);
2618 return SetPropertyAttributes(cx, obj,
2619 js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
2620 attrs, foundp);
2621 }
2623 JS_PUBLIC_API(JSBool)
2624 JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj,
2625 const jschar *name, size_t namelen,
2626 int8 tinyid, jsval value,
2627 JSPropertyOp getter, JSPropertyOp setter,
2628 uintN attrs)
2629 {
2630 CHECK_REQUEST(cx);
2631 return DefineUCProperty(cx, obj, name, namelen, value, getter, setter,
2632 attrs, SPROP_HAS_SHORTID, tinyid);
2633 }
2635 JS_PUBLIC_API(JSBool)
2636 JS_HasUCProperty(JSContext *cx, JSObject *obj,
2637 const jschar *name, size_t namelen,
2638 JSBool *vp)
2639 {
2640 JSBool ok;
2641 JSObject *obj2;
2642 JSProperty *prop;
2644 CHECK_REQUEST(cx);
2645 ok = LookupUCProperty(cx, obj, name, namelen, &obj2, &prop);
2646 if (ok) {
2647 *vp = (prop != NULL);
2648 if (prop)
2649 OBJ_DROP_PROPERTY(cx, obj2, prop);
2650 }
2651 return ok;
2652 }
2654 JS_PUBLIC_API(JSBool)
2655 JS_LookupUCProperty(JSContext *cx, JSObject *obj,
2656 const jschar *name, size_t namelen,
2657 jsval *vp)
2658 {
2659 JSBool ok;
2660 JSObject *obj2;
2661 JSProperty *prop;
2663 CHECK_REQUEST(cx);
2664 ok = LookupUCProperty(cx, obj, name, namelen, &obj2, &prop);
2665 if (ok)
2666 *vp = LookupResult(cx, obj, obj2, prop);
2667 return ok;
2668 }
2670 JS_PUBLIC_API(JSBool)
2671 JS_GetUCProperty(JSContext *cx, JSObject *obj,
2672 const jschar *name, size_t namelen,
2673 jsval *vp)
2674 {
2675 JSAtom *atom;
2677 CHECK_REQUEST(cx);
2678 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
2679 if (!atom)
2680 return JS_FALSE;
2681 return OBJ_GET_PROPERTY(cx, obj, (jsid)atom, vp);
2682 }
2684 JS_PUBLIC_API(JSBool)
2685 JS_SetUCProperty(JSContext *cx, JSObject *obj,
2686 const jschar *name, size_t namelen,
2687 jsval *vp)
2688 {
2689 JSAtom *atom;
2691 CHECK_REQUEST(cx);
2692 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
2693 if (!atom)
2694 return JS_FALSE;
2695 return OBJ_SET_PROPERTY(cx, obj, (jsid)atom, vp);
2696 }
2698 JS_PUBLIC_API(JSBool)
2699 JS_DeleteUCProperty2(JSContext *cx, JSObject *obj,
2700 const jschar *name, size_t namelen,
2701 jsval *rval)
2702 {
2703 JSAtom *atom;
2705 CHECK_REQUEST(cx);
2706 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
2707 if (!atom)
2708 return JS_FALSE;
2709 return OBJ_DELETE_PROPERTY(cx, obj, (jsid)atom, rval);
2710 }
2712 JS_PUBLIC_API(JSObject *)
2713 JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
2714 {
2715 CHECK_REQUEST(cx);
2716 /* NB: jsuint cast does ToUint32. */
2717 return js_NewArrayObject(cx, (jsuint)length, vector);
2718 }
2720 JS_PUBLIC_API(JSBool)
2721 JS_IsArrayObject(JSContext *cx, JSObject *obj)
2722 {
2723 return OBJ_GET_CLASS(cx, obj) == &js_ArrayClass;
2724 }
2726 JS_PUBLIC_API(JSBool)
2727 JS_GetArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
2728 {
2729 CHECK_REQUEST(cx);
2730 return js_GetLengthProperty(cx, obj, lengthp);
2731 }
2733 JS_PUBLIC_API(JSBool)
2734 JS_SetArrayLength(JSContext *cx, JSObject *obj, jsuint length)
2735 {
2736 CHECK_REQUEST(cx);
2737 return js_SetLengthProperty(cx, obj, length);
2738 }
2740 JS_PUBLIC_API(JSBool)
2741 JS_HasArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
2742 {
2743 CHECK_REQUEST(cx);
2744 return js_HasLengthProperty(cx, obj, lengthp);
2745 }
2747 JS_PUBLIC_API(JSBool)
2748 JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value,
2749 JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
2750 {
2751 CHECK_REQUEST(cx);
2752 return OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSVAL(index), value,
2753 getter, setter, attrs, NULL);
2754 }
2756 JS_PUBLIC_API(JSBool)
2757 JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
2758 {
2759 JSObject *obj2;
2760 JSProperty *prop;
2761 JSScopeProperty *sprop;
2762 JSBool ok;
2764 CHECK_REQUEST(cx);
2765 if (!LookupProperty(cx, obj, name, &obj2, &prop))
2766 return JS_FALSE;
2767 if (!prop) {
2768 js_ReportIsNotDefined(cx, name);
2769 return JS_FALSE;
2770 }
2771 if (obj2 != obj || !OBJ_IS_NATIVE(obj)) {
2772 char numBuf[12];
2773 OBJ_DROP_PROPERTY(cx, obj2, prop);
2774 JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)alias);
2775 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
2776 numBuf, name, OBJ_GET_CLASS(cx, obj2)->name);
2777 return JS_FALSE;
2778 }
2779 sprop = (JSScopeProperty *)prop;
2780 ok = (js_AddNativeProperty(cx, obj, INT_TO_JSVAL(alias),
2781 sprop->getter, sprop->setter, sprop->slot,
2782 sprop->attrs, sprop->flags | SPROP_IS_ALIAS,
2783 sprop->shortid)
2784 != NULL);
2785 OBJ_DROP_PROPERTY(cx, obj, prop);
2786 return ok;
2787 }
2789 JS_PUBLIC_API(JSBool)
2790 JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
2791 {
2792 JSBool ok;
2793 JSObject *obj2;
2794 JSProperty *prop;
2796 CHECK_REQUEST(cx);
2797 ok = OBJ_LOOKUP_PROPERTY(cx, obj, INT_TO_JSVAL(index), &obj2, &prop);
2798 if (ok) {
2799 *foundp = (prop != NULL);
2800 if (prop)
2801 OBJ_DROP_PROPERTY(cx, obj2, prop);
2802 }
2803 return ok;
2804 }
2806 JS_PUBLIC_API(JSBool)
2807 JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
2808 {
2809 JSBool ok;
2810 JSObject *obj2;
2811 JSProperty *prop;
2813 CHECK_REQUEST(cx);
2814 ok = OBJ_LOOKUP_PROPERTY(cx, obj, INT_TO_JSVAL(index), &obj2, &prop);
2815 if (ok)
2816 *vp = LookupResult(cx, obj, obj2, prop);
2817 return ok;
2818 }
2820 JS_PUBLIC_API(JSBool)
2821 JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
2822 {
2823 CHECK_REQUEST(cx);
2824 return OBJ_GET_PROPERTY(cx, obj, INT_TO_JSVAL(index), vp);
2825 }
2827 JS_PUBLIC_API(JSBool)
2828 JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
2829 {
2830 CHECK_REQUEST(cx);
2831 return OBJ_SET_PROPERTY(cx, obj, INT_TO_JSVAL(index), vp);
2832 }
2834 JS_PUBLIC_API(JSBool)
2835 JS_DeleteElement(JSContext *cx, JSObject *obj, jsint index)
2836 {
2837 jsval junk;
2839 CHECK_REQUEST(cx);
2840 return JS_DeleteElement2(cx, obj, index, &junk);
2841 }
2843 JS_PUBLIC_API(JSBool)
2844 JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval)
2845 {
2846 CHECK_REQUEST(cx);
2847 return OBJ_DELETE_PROPERTY(cx, obj, INT_TO_JSVAL(index), rval);
2848 }
2850 JS_PUBLIC_API(void)
2851 JS_ClearScope(JSContext *cx, JSObject *obj)
2852 {
2853 CHECK_REQUEST(cx);
2855 if (obj->map->ops->clear)
2856 obj->map->ops->clear(cx, obj);
2857 }
2859 JS_PUBLIC_API(JSIdArray *)
2860 JS_Enumerate(JSContext *cx, JSObject *obj)
2861 {
2862 jsint i, n;
2863 jsval iter_state, num_properties;
2864 jsid id;
2865 JSIdArray *ida;
2866 jsval *vector;
2868 CHECK_REQUEST(cx);
2870 ida = NULL;
2871 iter_state = JSVAL_NULL;
2873 /* Get the number of properties to enumerate. */
2874 if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, &num_properties))
2875 goto error;
2876 if (!JSVAL_IS_INT(num_properties)) {
2877 JS_ASSERT(0);
2878 goto error;
2879 }
2881 /* Grow as needed if we don't know the exact amount ahead of time. */
2882 n = JSVAL_TO_INT(num_properties);
2883 if (n <= 0)
2884 n = 8;
2886 /* Create an array of jsids large enough to hold all the properties */
2887 ida = js_NewIdArray(cx, n);
2888 if (!ida)
2889 goto error;
2891 i = 0;
2892 vector = &ida->vector[0];
2893 for (;;) {
2894 if (i == ida->length) {
2895 /* Grow length by factor of 1.5 instead of doubling. */
2896 jsint newlen = ida->length + (((jsuint)ida->length + 1) >> 1);
2897 ida = js_GrowIdArray(cx, ida, newlen);
2898 if (!ida)
2899 goto error;
2900 vector = &ida->vector[0];
2901 }
2903 if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &iter_state, &id))
2904 goto error;
2906 /* No more jsid's to enumerate ? */
2907 if (iter_state == JSVAL_NULL)
2908 break;
2909 vector[i++] = id;
2910 }
2911 ida->length = i;
2912 return ida;
2914 error:
2915 if (iter_state != JSVAL_NULL)
2916 OBJ_ENUMERATE(cx, obj, JSENUMERATE_DESTROY, &iter_state, 0);
2917 if (ida)
2918 JS_DestroyIdArray(cx, ida);
2919 return NULL;
2920 }
2922 JS_PUBLIC_API(JSBool)
2923 JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
2924 jsval *vp, uintN *attrsp)
2925 {
2926 CHECK_REQUEST(cx);
2927 return OBJ_CHECK_ACCESS(cx, obj, id, mode, vp, attrsp);
2928 }
2930 JS_PUBLIC_API(JSCheckAccessOp)
2931 JS_SetCheckObjectAccessCallback(JSRuntime *rt, JSCheckAccessOp acb)
2932 {
2933 JSCheckAccessOp oldacb;
2935 oldacb = rt->checkObjectAccess;
2936 rt->checkObjectAccess = acb;
2937 return oldacb;
2938 }
2940 static JSBool
2941 ReservedSlotIndexOK(JSContext *cx, JSObject *obj, JSClass *clasp,
2942 uint32 index, uint32 limit)
2943 {
2944 /* Check the computed, possibly per-instance, upper bound. */
2945 if (clasp->reserveSlots)
2946 JS_LOCK_OBJ_VOID(cx, obj, limit += clasp->reserveSlots(cx, obj));
2947 if (index >= limit) {
2948 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2949 JSMSG_RESERVED_SLOT_RANGE);
2950 return JS_FALSE;
2951 }
2952 return JS_TRUE;
2953 }
2955 JS_PUBLIC_API(JSBool)
2956 JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp)
2957 {
2958 JSClass *clasp;
2959 uint32 limit, slot;
2961 CHECK_REQUEST(cx);
2962 clasp = OBJ_GET_CLASS(cx, obj);
2963 limit = JSCLASS_RESERVED_SLOTS(clasp);
2964 if (index >= limit && !ReservedSlotIndexOK(cx, obj, clasp, index, limit))
2965 return JS_FALSE;
2966 slot = JSSLOT_START(clasp) + index;
2967 *vp = OBJ_GET_REQUIRED_SLOT(cx, obj, slot);
2968 return JS_TRUE;
2969 }
2971 JS_PUBLIC_API(JSBool)
2972 JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v)
2973 {
2974 JSClass *clasp;
2975 uint32 limit, slot;
2977 CHECK_REQUEST(cx);
2978 clasp = OBJ_GET_CLASS(cx, obj);
2979 limit = JSCLASS_RESERVED_SLOTS(clasp);
2980 if (index >= limit && !ReservedSlotIndexOK(cx, obj, clasp, index, limit))
2981 return JS_FALSE;
2982 slot = JSSLOT_START(clasp) + index;
2983 return OBJ_SET_REQUIRED_SLOT(cx, obj, slot, v);
2984 }
2986 #ifdef JS_THREADSAFE
2987 JS_PUBLIC_API(jsrefcount)
2988 JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals)
2989 {
2990 return JS_ATOMIC_INCREMENT(&principals->refcount);
2991 }
2993 JS_PUBLIC_API(jsrefcount)
2994 JS_DropPrincipals(JSContext *cx, JSPrincipals *principals)
2995 {
2996 jsrefcount rc = JS_ATOMIC_DECREMENT(&principals->refcount);
2997 if (rc == 0)
2998 principals->destroy(cx, principals);
2999 return rc;
3000 }
3001 #endif
3003 JS_PUBLIC_API(JSPrincipalsTranscoder)
3004 JS_SetPrincipalsTranscoder(JSRuntime *rt, JSPrincipalsTranscoder px)
3005 {
3006 JSPrincipalsTranscoder oldpx;
3008 oldpx = rt->principalsTranscoder;
3009 rt->principalsTranscoder = px;
3010 return oldpx;
3011 }
3013 JS_PUBLIC_API(JSObjectPrincipalsFinder)
3014 JS_SetObjectPrincipalsFinder(JSContext *cx, JSObjectPrincipalsFinder fop)
3015 {
3016 JSObjectPrincipalsFinder oldfop;
3018 oldfop = cx->findObjectPrincipals;
3019 cx->findObjectPrincipals = fop;
3020 return oldfop;
3021 }
3023 JS_PUBLIC_API(JSFunction *)
3024 JS_NewFunction(JSContext *cx, JSNative native, uintN nargs, uintN flags,
3025 JSObject *parent, const char *name)
3026 {
3027 JSAtom *atom;
3029 CHECK_REQUEST(cx);
3031 if (!name) {
3032 atom = NULL;
3033 } else {
3034 atom = js_Atomize(cx, name, strlen(name), 0);
3035 if (!atom)
3036 return NULL;
3037 }
3038 return js_NewFunction(cx, NULL, native, nargs, flags, parent, atom);
3039 }
3041 JS_PUBLIC_API(JSObject *)
3042 JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
3043 {
3044 CHECK_REQUEST(cx);
3045 if (OBJ_GET_CLASS(cx, funobj) != &js_FunctionClass) {
3046 /* Indicate we cannot clone this object. */
3047 return funobj;
3048 }
3049 return js_CloneFunctionObject(cx, funobj, parent);
3050 }
3052 JS_PUBLIC_API(JSObject *)
3053 JS_GetFunctionObject(JSFunction *fun)
3054 {
3055 return fun->object;
3056 }
3058 JS_PUBLIC_API(const char *)
3059 JS_GetFunctionName(JSFunction *fun)
3060 {
3061 return fun->atom
3062 ? JS_GetStringBytes(ATOM_TO_STRING(fun->atom))
3063 : js_anonymous_str;
3064 }
3066 JS_PUBLIC_API(JSString *)
3067 JS_GetFunctionId(JSFunction *fun)
3068 {
3069 return fun->atom ? ATOM_TO_STRING(fun->atom) : NULL;
3070 }
3072 JS_PUBLIC_API(uintN)
3073 JS_GetFunctionFlags(JSFunction *fun)
3074 {
3075 return fun->flags;
3076 }
3078 JS_PUBLIC_API(JSBool)
3079 JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
3080 {
3081 return OBJ_GET_CLASS(cx, obj) == &js_FunctionClass;
3082 }
3084 JS_PUBLIC_API(JSBool)
3085 JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs)
3086 {
3087 JSFunction *fun;
3089 CHECK_REQUEST(cx);
3090 for (; fs->name; fs++) {
3091 fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs,
3092 fs->flags);
3093 if (!fun)
3094 return JS_FALSE;
3095 fun->extra = fs->extra;
3096 }
3097 return JS_TRUE;
3098 }
3100 JS_PUBLIC_API(JSFunction *)
3101 JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call,
3102 uintN nargs, uintN attrs)
3103 {
3104 JSAtom *atom;
3106 CHECK_REQUEST(cx);
3107 atom = js_Atomize(cx, name, strlen(name), 0);
3108 if (!atom)
3109 return NULL;
3110 return js_DefineFunction(cx, obj, atom, call, nargs, attrs);
3111 }
3113 JS_PUBLIC_API(JSFunction *)
3114 JS_DefineUCFunction(JSContext *cx, JSObject *obj,
3115 const jschar *name, size_t namelen, JSNative call,
3116 uintN nargs, uintN attrs)
3117 {
3118 JSAtom *atom;
3120 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3121 if (!atom)
3122 return NULL;
3123 return js_DefineFunction(cx, obj, atom, call, nargs, attrs);
3124 }
3126 static JSScript *
3127 CompileTokenStream(JSContext *cx, JSObject *obj, JSTokenStream *ts,
3128 void *tempMark, JSBool *eofp)
3129 {
3130 JSBool eof;
3131 JSArenaPool codePool, notePool;
3132 JSCodeGenerator cg;
3133 JSScript *script;
3135 CHECK_REQUEST(cx);
3136 eof = JS_FALSE;
3137 JS_InitArenaPool(&codePool, "code", 1024, sizeof(jsbytecode));
3138 JS_InitArenaPool(¬ePool, "note", 1024, sizeof(jssrcnote));
3139 if (!js_InitCodeGenerator(cx, &cg, &codePool, ¬ePool,
3140 ts->filename, ts->lineno,
3141 ts->principals)) {
3142 script = NULL;
3143 } else if (!js_CompileTokenStream(cx, obj, ts, &cg)) {
3144 script = NULL;
3145 eof = (ts->flags & TSF_EOF) != 0;
3146 } else {
3147 script = js_NewScriptFromCG(cx, &cg, NULL);
3148 }
3149 if (eofp)
3150 *eofp = eof;
3151 if (!js_CloseTokenStream(cx, ts)) {
3152 if (script)
3153 js_DestroyScript(cx, script);
3154 script = NULL;
3155 }
3156 cg.tempMark = tempMark;
3157 js_FinishCodeGenerator(cx, &cg);
3158 JS_FinishArenaPool(&codePool);
3159 JS_FinishArenaPool(¬ePool);
3160 return script;
3161 }
3163 JS_PUBLIC_API(JSScript *)
3164 JS_CompileScript(JSContext *cx, JSObject *obj,
3165 const char *bytes, size_t length,
3166 const char *filename, uintN lineno)
3167 {
3168 jschar *chars;
3169 JSScript *script;
3171 CHECK_REQUEST(cx);
3172 chars = js_InflateString(cx, bytes, length);
3173 if (!chars)
3174 return NULL;
3175 script = JS_CompileUCScript(cx, obj, chars, length, filename, lineno);
3176 JS_free(cx, chars);
3177 return script;
3178 }
3180 JS_PUBLIC_API(JSScript *)
3181 JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj,
3182 JSPrincipals *principals,
3183 const char *bytes, size_t length,
3184 const char *filename, uintN lineno)
3185 {
3186 jschar *chars;
3187 JSScript *script;
3189 CHECK_REQUEST(cx);
3190 chars = js_InflateString(cx, bytes, length);
3191 if (!chars)
3192 return NULL;
3193 script = JS_CompileUCScriptForPrincipals(cx, obj, principals,
3194 chars, length, filename, lineno);
3195 JS_free(cx, chars);
3196 return script;
3197 }
3199 JS_PUBLIC_API(JSScript *)
3200 JS_CompileUCScript(JSContext *cx, JSObject *obj,
3201 const jschar *chars, size_t length,
3202 const char *filename, uintN lineno)
3203 {
3204 CHECK_REQUEST(cx);
3205 return JS_CompileUCScriptForPrincipals(cx, obj, NULL, chars, length,
3206 filename, lineno);
3207 }
3209 JS_PUBLIC_API(JSScript *)
3210 JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj,
3211 JSPrincipals *principals,
3212 const jschar *chars, size_t length,
3213 const char *filename, uintN lineno)
3214 {
3215 void *mark;
3216 JSTokenStream *ts;
3217 JSScript *script;
3219 CHECK_REQUEST(cx);
3220 mark = JS_ARENA_MARK(&cx->tempPool);
3221 ts = js_NewTokenStream(cx, chars, length, filename, lineno, principals);
3222 if (!ts)
3223 return NULL;
3224 script = CompileTokenStream(cx, obj, ts, mark, NULL);
3225 #if JS_HAS_EXCEPTIONS
3226 if (!script && !cx->fp)
3227 js_ReportUncaughtException(cx);
3228 #endif
3229 return script;
3230 }
3232 JS_PUBLIC_API(JSBool)
3233 JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj,
3234 const char *bytes, size_t length)
3235 {
3236 jschar *chars;
3237 JSBool result;
3238 JSExceptionState *exnState;
3239 void *tempMark;
3240 JSTokenStream *ts;
3241 JSErrorReporter older;
3243 CHECK_REQUEST(cx);
3244 chars = js_InflateString(cx, bytes, length);
3245 if (!chars)
3246 return JS_TRUE;
3248 /*
3249 * Return true on any out-of-memory error, so our caller doesn't try to
3250 * collect more buffered source.
3251 */
3252 result = JS_TRUE;
3253 exnState = JS_SaveExceptionState(cx);
3254 tempMark = JS_ARENA_MARK(&cx->tempPool);
3255 ts = js_NewTokenStream(cx, chars, length, NULL, 0, NULL);
3256 if (ts) {
3257 older = JS_SetErrorReporter(cx, NULL);
3258 if (!js_ParseTokenStream(cx, obj, ts)) {
3259 /*
3260 * We ran into an error. If it was because we ran out of source,
3261 * we return false, so our caller will know to try to collect more
3262 * buffered source.
3263 */
3264 result = (ts->flags & TSF_EOF) == 0;
3265 }
3267 JS_SetErrorReporter(cx, older);
3268 js_CloseTokenStream(cx, ts);
3269 JS_ARENA_RELEASE(&cx->tempPool, tempMark);
3270 }
3272 JS_free(cx, chars);
3273 JS_RestoreExceptionState(cx, exnState);
3274 return result;
3275 }
3277 JS_PUBLIC_API(JSScript *)
3278 JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
3279 {
3280 void *mark;
3281 JSTokenStream *ts;
3282 JSScript *script;
3284 CHECK_REQUEST(cx);
3285 mark = JS_ARENA_MARK(&cx->tempPool);
3286 ts = js_NewFileTokenStream(cx, filename, stdin);
3287 if (!ts)
3288 return NULL;
3289 script = CompileTokenStream(cx, obj, ts, mark, NULL);
3290 #if JS_HAS_EXCEPTIONS
3291 if (!script && !cx->fp)
3292 js_ReportUncaughtException(cx);
3293 #endif
3294 return script;
3295 }
3297 JS_PUBLIC_API(JSScript *)
3298 JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename,
3299 FILE *file)
3300 {
3301 return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, NULL);
3302 }
3304 JS_PUBLIC_API(JSScript *)
3305 JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj,
3306 const char *filename, FILE *file,
3307 JSPrincipals *principals)
3308 {
3309 void *mark;
3310 JSTokenStream *ts;
3311 JSScript *script;
3313 CHECK_REQUEST(cx);
3314 mark = JS_ARENA_MARK(&cx->tempPool);
3315 ts = js_NewFileTokenStream(cx, NULL, file);
3316 if (!ts)
3317 return NULL;
3318 ts->filename = filename;
3319 /* XXXshaver js_NewFileTokenStream should do this, because it drops */
3320 if (principals) {
3321 ts->principals = principals;
3322 JSPRINCIPALS_HOLD(cx, ts->principals);
3323 }
3324 script = CompileTokenStream(cx, obj, ts, mark, NULL);
3325 #if JS_HAS_EXCEPTIONS
3326 if (!script && !cx->fp)
3327 js_ReportUncaughtException(cx);
3328 #endif
3329 return script;
3330 }
3332 JS_PUBLIC_API(JSObject *)
3333 JS_NewScriptObject(JSContext *cx, JSScript *script)
3334 {
3335 JSObject *obj;
3337 obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL);
3338 if (!obj)
3339 return NULL;
3341 if (script) {
3342 if (!JS_SetPrivate(cx, obj, script))
3343 return NULL;
3344 script->object = obj;
3345 }
3346 return obj;
3347 }
3349 JS_PUBLIC_API(JSObject *)
3350 JS_GetScriptObject(JSScript *script)
3351 {
3352 return script->object;
3353 }
3355 JS_PUBLIC_API(void)
3356 JS_DestroyScript(JSContext *cx, JSScript *script)
3357 {
3358 CHECK_REQUEST(cx);
3359 js_DestroyScript(cx, script);
3360 }
3362 JS_PUBLIC_API(JSFunction *)
3363 JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name,
3364 uintN nargs, const char **argnames,
3365 const char *bytes, size_t length,
3366 const char *filename, uintN lineno)
3367 {
3368 jschar *chars;
3369 JSFunction *fun;
3371 CHECK_REQUEST(cx);
3372 chars = js_InflateString(cx, bytes, length);
3373 if (!chars)
3374 return NULL;
3375 fun = JS_CompileUCFunction(cx, obj, name, nargs, argnames, chars, length,
3376 filename, lineno);
3377 JS_free(cx, chars);
3378 return fun;
3379 }
3381 JS_PUBLIC_API(JSFunction *)
3382 JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj,
3383 JSPrincipals *principals, const char *name,
3384 uintN nargs, const char **argnames,
3385 const char *bytes, size_t length,
3386 const char *filename, uintN lineno)
3387 {
3388 jschar *chars;
3389 JSFunction *fun;
3391 CHECK_REQUEST(cx);
3392 chars = js_InflateString(cx, bytes, length);
3393 if (!chars)
3394 return NULL;
3395 fun = JS_CompileUCFunctionForPrincipals(cx, obj, principals, name,
3396 nargs, argnames, chars, length,
3397 filename, lineno);
3398 JS_free(cx, chars);
3399 return fun;
3400 }
3402 JS_PUBLIC_API(JSFunction *)
3403 JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name,
3404 uintN nargs, const char **argnames,
3405 const jschar *chars, size_t length,
3406 const char *filename, uintN lineno)
3407 {
3408 CHECK_REQUEST(cx);
3409 return JS_CompileUCFunctionForPrincipals(cx, obj, NULL, name,
3410 nargs, argnames,
3411 chars, length,
3412 filename, lineno);
3413 }
3415 JS_PUBLIC_API(JSFunction *)
3416 JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
3417 JSPrincipals *principals, const char *name,
3418 uintN nargs, const char **argnames,
3419 const jschar *chars, size_t length,
3420 const char *filename, uintN lineno)
3421 {
3422 void *mark;
3423 JSTokenStream *ts;
3424 JSFunction *fun;
3425 JSAtom *funAtom, *argAtom;
3426 uintN i;
3428 CHECK_REQUEST(cx);
3429 mark = JS_ARENA_MARK(&cx->tempPool);
3430 ts = js_NewTokenStream(cx, chars, length, filename, lineno, principals);
3431 if (!ts) {
3432 fun = NULL;
3433 goto out;
3434 }
3435 if (!name) {
3436 funAtom = NULL;
3437 } else {
3438 funAtom = js_Atomize(cx, name, strlen(name), 0);
3439 if (!funAtom) {
3440 fun = NULL;
3441 goto out;
3442 }
3443 }
3444 fun = js_NewFunction(cx, NULL, NULL, nargs, 0, obj, funAtom);
3445 if (!fun)
3446 goto out;
3447 if (nargs) {
3448 for (i = 0; i < nargs; i++) {
3449 argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
3450 if (!argAtom)
3451 break;
3452 if (!js_AddNativeProperty(cx, fun->object, (jsid)argAtom,
3453 js_GetArgument, js_SetArgument,
3454 SPROP_INVALID_SLOT,
3455 JSPROP_ENUMERATE | JSPROP_PERMANENT |
3456 JSPROP_SHARED,
3457 SPROP_HAS_SHORTID, i)) {
3458 break;
3459 }
3460 }
3461 if (i < nargs) {
3462 fun = NULL;
3463 goto out;
3464 }
3465 }
3466 if (!js_CompileFunctionBody(cx, ts, fun)) {
3467 fun = NULL;
3468 goto out;
3469 }
3470 if (obj && funAtom) {
3471 if (!OBJ_DEFINE_PROPERTY(cx, obj, (jsid)funAtom,
3472 OBJECT_TO_JSVAL(fun->object),
3473 NULL, NULL, 0, NULL)) {
3474 return NULL;
3475 }
3476 }
3477 out:
3478 if (ts)
3479 js_CloseTokenStream(cx, ts);
3480 JS_ARENA_RELEASE(&cx->tempPool, mark);
3481 #if JS_HAS_EXCEPTIONS
3482 if (!fun && !cx->fp)
3483 js_ReportUncaughtException(cx);
3484 #endif
3485 return fun;
3486 }
3488 JS_PUBLIC_API(JSString *)
3489 JS_DecompileScript(JSContext *cx, JSScript *script, const char *name,
3490 uintN indent)
3491 {
3492 JSPrinter *jp;
3493 JSString *str;
3495 CHECK_REQUEST(cx);
3496 jp = js_NewPrinter(cx, name,
3497 indent & ~JS_DONT_PRETTY_PRINT,
3498 !(indent & JS_DONT_PRETTY_PRINT));
3499 if (!jp)
3500 return NULL;
3501 if (js_DecompileScript(jp, script))
3502 str = js_GetPrinterOutput(jp);
3503 else
3504 str = NULL;
3505 js_DestroyPrinter(jp);
3506 return str;
3507 }
3509 JS_PUBLIC_API(JSString *)
3510 JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent)
3511 {
3512 JSPrinter *jp;
3513 JSString *str;
3515 CHECK_REQUEST(cx);
3516 jp = js_NewPrinter(cx, JS_GetFunctionName(fun),
3517 indent & ~JS_DONT_PRETTY_PRINT,
3518 !(indent & JS_DONT_PRETTY_PRINT));
3519 if (!jp)
3520 return NULL;
3521 if (js_DecompileFunction(jp, fun))
3522 str = js_GetPrinterOutput(jp);
3523 else
3524 str = NULL;
3525 js_DestroyPrinter(jp);
3526 return str;
3527 }
3529 JS_PUBLIC_API(JSString *)
3530 JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent)
3531 {
3532 JSPrinter *jp;
3533 JSString *str;
3535 CHECK_REQUEST(cx);
3536 jp = js_NewPrinter(cx, JS_GetFunctionName(fun),
3537 indent & ~JS_DONT_PRETTY_PRINT,
3538 !(indent & JS_DONT_PRETTY_PRINT));
3539 if (!jp)
3540 return NULL;
3541 if (js_DecompileFunctionBody(jp, fun))
3542 str = js_GetPrinterOutput(jp);
3543 else
3544 str = NULL;
3545 js_DestroyPrinter(jp);
3546 return str;
3547 }
3549 JS_PUBLIC_API(JSBool)
3550 JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
3551 {
3552 CHECK_REQUEST(cx);
3553 if (!js_Execute(cx, obj, script, NULL, 0, rval)) {
3554 #if JS_HAS_EXCEPTIONS
3555 if (!cx->fp)
3556 js_ReportUncaughtException(cx);
3557 #endif
3558 return JS_FALSE;
3559 }
3560 return JS_TRUE;
3561 }
3563 JS_PUBLIC_API(JSBool)
3564 JS_ExecuteScriptPart(JSContext *cx, JSObject *obj, JSScript *script,
3565 JSExecPart part, jsval *rval)
3566 {
3567 JSScript tmp;
3568 JSRuntime *rt;
3569 JSBool ok;
3571 /* Make a temporary copy of the JSScript structure and farble it a bit. */
3572 tmp = *script;
3573 if (part == JSEXEC_PROLOG) {
3574 tmp.length = PTRDIFF(tmp.main, tmp.code, jsbytecode);
3575 } else {
3576 tmp.length -= PTRDIFF(tmp.main, tmp.code, jsbytecode);
3577 tmp.code = tmp.main;
3578 }
3580 /* Tell the debugger about our temporary copy of the script structure. */
3581 rt = cx->runtime;
3582 if (rt->newScriptHook) {
3583 rt->newScriptHook(cx, tmp.filename, tmp.lineno, &tmp, NULL,
3584 rt->newScriptHookData);
3585 }
3587 /* Execute the farbled struct and tell the debugger to forget about it. */
3588 ok = JS_ExecuteScript(cx, obj, &tmp, rval);
3589 if (rt->destroyScriptHook)
3590 rt->destroyScriptHook(cx, &tmp, rt->destroyScriptHookData);
3591 return ok;
3592 }
3594 JS_PUBLIC_API(JSBool)
3595 JS_EvaluateScript(JSContext *cx, JSObject *obj,
3596 const char *bytes, uintN length,
3597 const char *filename, uintN lineno,
3598 jsval *rval)
3599 {
3600 jschar *chars;
3601 JSBool ok;
3603 CHECK_REQUEST(cx);
3604 chars = js_InflateString(cx, bytes, length);
3605 if (!chars)
3606 return JS_FALSE;
3607 ok = JS_EvaluateUCScript(cx, obj, chars, length, filename, lineno, rval);
3608 JS_free(cx, chars);
3609 return ok;
3610 }
3612 JS_PUBLIC_API(JSBool)
3613 JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj,
3614 JSPrincipals *principals,
3615 const char *bytes, uintN length,
3616 const char *filename, uintN lineno,
3617 jsval *rval)
3618 {
3619 jschar *chars;
3620 JSBool ok;
3622 CHECK_REQUEST(cx);
3623 chars = js_InflateString(cx, bytes, length);
3624 if (!chars)
3625 return JS_FALSE;
3626 ok = JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length,
3627 filename, lineno, rval);
3628 JS_free(cx, chars);
3629 return ok;
3630 }
3632 JS_PUBLIC_API(JSBool)
3633 JS_EvaluateUCScript(JSContext *cx, JSObject *obj,
3634 const jschar *chars, uintN length,
3635 const char *filename, uintN lineno,
3636 jsval *rval)
3637 {
3638 CHECK_REQUEST(cx);
3639 return JS_EvaluateUCScriptForPrincipals(cx, obj, NULL, chars, length,
3640 filename, lineno, rval);
3641 }
3643 JS_PUBLIC_API(JSBool)
3644 JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
3645 JSPrincipals *principals,
3646 const jschar *chars, uintN length,
3647 const char *filename, uintN lineno,
3648 jsval *rval)
3649 {
3650 uint32 options;
3651 JSScript *script;
3652 JSBool ok;
3654 CHECK_REQUEST(cx);
3655 options = cx->options;
3656 cx->options = options | JSOPTION_COMPILE_N_GO;
3657 script = JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length,
3658 filename, lineno);
3659 cx->options = options;
3660 if (!script)
3661 return JS_FALSE;
3662 ok = js_Execute(cx, obj, script, NULL, 0, rval);
3663 #if JS_HAS_EXCEPTIONS
3664 if (!ok && !cx->fp)
3665 js_ReportUncaughtException(cx);
3666 #endif
3667 JS_DestroyScript(cx, script);
3668 return ok;
3669 }
3671 JS_PUBLIC_API(JSBool)
3672 JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc,
3673 jsval *argv, jsval *rval)
3674 {
3675 CHECK_REQUEST(cx);
3676 if (!js_InternalCall(cx, obj, OBJECT_TO_JSVAL(fun->object), argc, argv,
3677 rval)) {
3678 #if JS_HAS_EXCEPTIONS
3679 if (!cx->fp)
3680 js_ReportUncaughtException(cx);
3681 #endif
3682 return JS_FALSE;
3683 }
3684 return JS_TRUE;
3685 }
3687 JS_PUBLIC_API(JSBool)
3688 JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc,
3689 jsval *argv, jsval *rval)
3690 {
3691 jsval fval;
3693 CHECK_REQUEST(cx);
3694 if (!JS_GetProperty(cx, obj, name, &fval))
3695 return JS_FALSE;
3696 if (!js_InternalCall(cx, obj, fval, argc, argv, rval)) {
3697 #if JS_HAS_EXCEPTIONS
3698 if (!cx->fp)
3699 js_ReportUncaughtException(cx);
3700 #endif
3701 return JS_FALSE;
3702 }
3703 return JS_TRUE;
3704 }
3706 JS_PUBLIC_API(JSBool)
3707 JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc,
3708 jsval *argv, jsval *rval)
3709 {
3710 CHECK_REQUEST(cx);
3711 if (!js_InternalCall(cx, obj, fval, argc, argv, rval)) {
3712 #if JS_HAS_EXCEPTIONS
3713 if (!cx->fp)
3714 js_ReportUncaughtException(cx);
3715 #endif
3716 return JS_FALSE;
3717 }
3718 return JS_TRUE;
3719 }
3721 JS_PUBLIC_API(JSBranchCallback)
3722 JS_SetBranchCallback(JSContext *cx, JSBranchCallback cb)
3723 {
3724 JSBranchCallback oldcb;
3726 oldcb = cx->branchCallback;
3727 cx->branchCallback = cb;
3728 return oldcb;
3729 }
3731 JS_PUBLIC_API(JSBool)
3732 JS_IsRunning(JSContext *cx)
3733 {
3734 return cx->fp != NULL;
3735 }
3737 JS_PUBLIC_API(JSBool)
3738 JS_IsConstructing(JSContext *cx)
3739 {
3740 return cx->fp && (cx->fp->flags & JSFRAME_CONSTRUCTING);
3741 }
3743 JS_FRIEND_API(JSBool)
3744 JS_IsAssigning(JSContext *cx)
3745 {
3746 JSStackFrame *fp;
3747 jsbytecode *pc;
3749 for (fp = cx->fp; fp && !fp->script; fp = fp->down)
3750 continue;
3751 if (!fp || !(pc = fp->pc))
3752 return JS_FALSE;
3753 return (js_CodeSpec[*pc].format & JOF_ASSIGNING) != 0;
3754 }
3756 JS_PUBLIC_API(void)
3757 JS_SetCallReturnValue2(JSContext *cx, jsval v)
3758 {
3759 #if JS_HAS_LVALUE_RETURN
3760 cx->rval2 = v;
3761 cx->rval2set = JS_TRUE;
3762 #endif
3763 }
3765 /************************************************************************/
3767 JS_PUBLIC_API(JSString *)
3768 JS_NewString(JSContext *cx, char *bytes, size_t length)
3769 {
3770 jschar *chars;
3771 JSString *str;
3773 CHECK_REQUEST(cx);
3774 /* Make a Unicode vector from the 8-bit char codes in bytes. */
3775 chars = js_InflateString(cx, bytes, length);
3776 if (!chars)
3777 return NULL;
3779 /* Free chars (but not bytes, which caller frees on error) if we fail. */
3780 str = js_NewString(cx, chars, length, 0);
3781 if (!str) {
3782 JS_free(cx, chars);
3783 return NULL;
3784 }
3786 /* Hand off bytes to the deflated string cache, if possible. */
3787 if (!js_SetStringBytes(str, bytes, length))
3788 JS_free(cx, bytes);
3789 return str;
3790 }
3792 JS_PUBLIC_API(JSString *)
3793 JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
3794 {
3795 jschar *js;
3796 JSString *str;
3798 CHECK_REQUEST(cx);
3799 js = js_InflateString(cx, s, n);
3800 if (!js)
3801 return NULL;
3802 str = js_NewString(cx, js, n, 0);
3803 if (!str)
3804 JS_free(cx, js);
3805 return str;
3806 }
3808 JS_PUBLIC_API(JSString *)
3809 JS_NewStringCopyZ(JSContext *cx, const char *s)
3810 {
3811 size_t n;
3812 jschar *js;
3813 JSString *str;
3815 CHECK_REQUEST(cx);
3816 if (!s)
3817 return cx->runtime->emptyString;
3818 n = strlen(s);
3819 js = js_InflateString(cx, s, n);
3820 if (!js)
3821 return NULL;
3822 str = js_NewString(cx, js, n, 0);
3823 if (!str)
3824 JS_free(cx, js);
3825 return str;
3826 }
3828 JS_PUBLIC_API(JSString *)
3829 JS_InternString(JSContext *cx, const char *s)
3830 {
3831 JSAtom *atom;
3833 CHECK_REQUEST(cx);
3834 atom = js_Atomize(cx, s, strlen(s), ATOM_INTERNED);
3835 if (!atom)
3836 return NULL;
3837 return ATOM_TO_STRING(atom);
3838 }
3840 JS_PUBLIC_API(JSString *)
3841 JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
3842 {
3843 CHECK_REQUEST(cx);
3844 return js_NewString(cx, chars, length, 0);
3845 }
3847 JS_PUBLIC_API(JSString *)
3848 JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n)
3849 {
3850 CHECK_REQUEST(cx);
3851 return js_NewStringCopyN(cx, s, n, 0);
3852 }
3854 JS_PUBLIC_API(JSString *)
3855 JS_NewUCStringCopyZ(JSContext *cx, const jschar *s)
3856 {
3857 CHECK_REQUEST(cx);
3858 if (!s)
3859 return cx->runtime->emptyString;
3860 return js_NewStringCopyZ(cx, s, 0);
3861 }
3863 JS_PUBLIC_API(JSString *)
3864 JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
3865 {
3866 JSAtom *atom;
3868 CHECK_REQUEST(cx);
3869 atom = js_AtomizeChars(cx, s, length, ATOM_INTERNED);
3870 if (!atom)
3871 return NULL;
3872 return ATOM_TO_STRING(atom);
3873 }
3875 JS_PUBLIC_API(JSString *)
3876 JS_InternUCString(JSContext *cx, const jschar *s)
3877 {
3878 return JS_InternUCStringN(cx, s, js_strlen(s));
3879 }
3881 JS_PUBLIC_API(char *)
3882 JS_GetStringBytes(JSString *str)
3883 {
3884 char *bytes;
3886 bytes = js_GetStringBytes(str);
3887 return bytes ? bytes : "";
3888 }
3890 JS_PUBLIC_API(jschar *)
3891 JS_GetStringChars(JSString *str)
3892 {
3893 /*
3894 * API botch (again, shades of JS_GetStringBytes): we have no cx to pass
3895 * to js_UndependString (called by js_GetStringChars) for out-of-memory
3896 * error reports, so js_UndependString passes NULL and suppresses errors.
3897 * If it fails to convert a dependent string into an independent one, our
3898 * caller will not be guaranteed a \u0000 terminator as a backstop. This
3899 * may break some clients who already misbehave on embedded NULs.
3900 *
3901 * The gain of dependent strings, which cure quadratic and cubic growth
3902 * rate bugs in string concatenation, is worth this slight loss in API
3903 * compatibility.
3904 */
3905 jschar *chars;
3907 chars = js_GetStringChars(str);
3908 return chars ? chars : JSSTRING_CHARS(str);
3909 }
3911 JS_PUBLIC_API(size_t)
3912 JS_GetStringLength(JSString *str)
3913 {
3914 return JSSTRING_LENGTH(str);
3915 }
3917 JS_PUBLIC_API(intN)
3918 JS_CompareStrings(JSString *str1, JSString *str2)
3919 {
3920 return js_CompareStrings(str1, str2);
3921 }
3923 JS_PUBLIC_API(JSString *)
3924 JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length)
3925 {
3926 CHECK_REQUEST(cx);
3927 return js_NewString(cx, chars, length, GCF_MUTABLE);
3928 }
3930 JS_PUBLIC_API(JSString *)
3931 JS_NewDependentString(JSContext *cx, JSString *str, size_t start,
3932 size_t length)
3933 {
3934 CHECK_REQUEST(cx);
3935 return js_NewDependentString(cx, str, start, length, 0);
3936 }
3938 JS_PUBLIC_API(JSString *)
3939 JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
3940 {
3941 CHECK_REQUEST(cx);
3942 return js_ConcatStrings(cx, left, right);
3943 }
3945 JS_PUBLIC_API(const jschar *)
3946 JS_UndependString(JSContext *cx, JSString *str)
3947 {
3948 CHECK_REQUEST(cx);
3949 return js_UndependString(cx, str);
3950 }
3952 JS_PUBLIC_API(JSBool)
3953 JS_MakeStringImmutable(JSContext *cx, JSString *str)
3954 {
3955 CHECK_REQUEST(cx);
3956 if (!js_UndependString(cx, str))
3957 return JS_FALSE;
3959 *js_GetGCThingFlags(str) &= ~GCF_MUTABLE;
3960 return JS_TRUE;
3961 }
3963 /************************************************************************/
3965 JS_PUBLIC_API(void)
3966 JS_ReportError(JSContext *cx, const char *format, ...)
3967 {
3968 va_list ap;
3970 va_start(ap, format);
3971 js_ReportErrorVA(cx, JSREPORT_ERROR, format, ap);
3972 va_end(ap);
3973 }
3975 JS_PUBLIC_API(void)
3976 JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback,
3977 void *userRef, const uintN errorNumber, ...)
3978 {
3979 va_list ap;
3981 va_start(ap, errorNumber);
3982 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
3983 errorNumber, JS_TRUE, ap);
3984 va_end(ap);
3985 }
3987 JS_PUBLIC_API(void)
3988 JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
3989 void *userRef, const uintN errorNumber, ...)
3990 {
3991 va_list ap;
3993 va_start(ap, errorNumber);
3994 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
3995 errorNumber, JS_FALSE, ap);
3996 va_end(ap);
3997 }
3999 JS_PUBLIC_API(JSBool)
4000 JS_ReportWarning(JSContext *cx, const char *format, ...)
4001 {
4002 va_list ap;
4003 JSBool ok;
4005 va_start(ap, format);
4006 ok = js_ReportErrorVA(cx, JSREPORT_WARNING, format, ap);
4007 va_end(ap);
4008 return ok;
4009 }
4011 JS_PUBLIC_API(JSBool)
4012 JS_ReportErrorFlagsAndNumber(JSContext *cx, uintN flags,
4013 JSErrorCallback errorCallback, void *userRef,
4014 const uintN errorNumber, ...)
4015 {
4016 va_list ap;
4017 JSBool ok;
4019 va_start(ap, errorNumber);
4020 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
4021 errorNumber, JS_TRUE, ap);
4022 va_end(ap);
4023 return ok;
4024 }
4026 JS_PUBLIC_API(JSBool)
4027 JS_ReportErrorFlagsAndNumberUC(JSContext *cx, uintN flags,
4028 JSErrorCallback errorCallback, void *userRef,
4029 const uintN errorNumber, ...)
4030 {
4031 va_list ap;
4032 JSBool ok;
4034 va_start(ap, errorNumber);
4035 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
4036 errorNumber, JS_FALSE, ap);
4037 va_end(ap);
4038 return ok;
4039 }
4041 JS_PUBLIC_API(void)
4042 JS_ReportOutOfMemory(JSContext *cx)
4043 {
4044 js_ReportOutOfMemory(cx, js_GetErrorMessage);
4045 }
4047 JS_PUBLIC_API(JSErrorReporter)
4048 JS_SetErrorReporter(JSContext *cx, JSErrorReporter er)
4049 {
4050 JSErrorReporter older;
4052 older = cx->errorReporter;
4053 cx->errorReporter = er;
4054 return older;
4055 }
4057 /************************************************************************/
4059 /*
4060 * Regular Expressions.
4061 */
4062 JS_PUBLIC_API(JSObject *)
4063 JS_NewRegExpObject(JSContext *cx, char *bytes, size_t length, uintN flags)
4064 {
4065 #if JS_HAS_REGEXPS
4066 jschar *chars;
4067 JSObject *obj;
4069 CHECK_REQUEST(cx);
4070 chars = js_InflateString(cx, bytes, length);
4071 if (!chars)
4072 return NULL;
4073 obj = js_NewRegExpObject(cx, NULL, chars, length, flags);
4074 JS_free(cx, chars);
4075 return obj;
4076 #else
4077 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_REG_EXPS);
4078 return NULL;
4079 #endif
4080 }
4082 JS_PUBLIC_API(JSObject *)
4083 JS_NewUCRegExpObject(JSContext *cx, jschar *chars, size_t length, uintN flags)
4084 {
4085 CHECK_REQUEST(cx);
4086 #if JS_HAS_REGEXPS
4087 return js_NewRegExpObject(cx, NULL, chars, length, flags);
4088 #else
4089 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_REG_EXPS);
4090 return NULL;
4091 #endif
4092 }
4094 JS_PUBLIC_API(void)
4095 JS_SetRegExpInput(JSContext *cx, JSString *input, JSBool multiline)
4096 {
4097 JSRegExpStatics *res;
4099 CHECK_REQUEST(cx);
4100 /* No locking required, cx is thread-private and input must be live. */
4101 res = &cx->regExpStatics;
4102 res->input = input;
4103 res->multiline = multiline;
4104 cx->runtime->gcPoke = JS_TRUE;
4105 }
4107 JS_PUBLIC_API(void)
4108 JS_ClearRegExpStatics(JSContext *cx)
4109 {
4110 JSRegExpStatics *res;
4112 /* No locking required, cx is thread-private and input must be live. */
4113 res = &cx->regExpStatics;
4114 res->input = NULL;
4115 res->multiline = JS_FALSE;
4116 res->parenCount = 0;
4117 res->lastMatch = res->lastParen = js_EmptySubString;
4118 res->leftContext = res->rightContext = js_EmptySubString;
4119 cx->runtime->gcPoke = JS_TRUE;
4120 }
4122 JS_PUBLIC_API(void)
4123 JS_ClearRegExpRoots(JSContext *cx)
4124 {
4125 JSRegExpStatics *res;
4127 /* No locking required, cx is thread-private and input must be live. */
4128 res = &cx->regExpStatics;
4129 res->input = NULL;
4130 cx->runtime->gcPoke = JS_TRUE;
4131 }
4133 /* TODO: compile, execute, get/set other statics... */
4135 /************************************************************************/
4137 JS_PUBLIC_API(void)
4138 JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks)
4139 {
4140 cx->localeCallbacks = callbacks;
4141 }
4143 JS_PUBLIC_API(JSLocaleCallbacks *)
4144 JS_GetLocaleCallbacks(JSContext *cx)
4145 {
4146 return cx->localeCallbacks;
4147 }
4149 /************************************************************************/
4151 JS_PUBLIC_API(JSBool)
4152 JS_IsExceptionPending(JSContext *cx)
4153 {
4154 #if JS_HAS_EXCEPTIONS
4155 return (JSBool) cx->throwing;
4156 #else
4157 return JS_FALSE;
4158 #endif
4159 }
4161 JS_PUBLIC_API(JSBool)
4162 JS_GetPendingException(JSContext *cx, jsval *vp)
4163 {
4164 #if JS_HAS_EXCEPTIONS
4165 CHECK_REQUEST(cx);
4166 if (!cx->throwing)
4167 return JS_FALSE;
4168 *vp = cx->exception;
4169 return JS_TRUE;
4170 #else
4171 return JS_FALSE;
4172 #endif
4173 }
4175 JS_PUBLIC_API(void)
4176 JS_SetPendingException(JSContext *cx, jsval v)
4177 {
4178 CHECK_REQUEST(cx);
4179 #if JS_HAS_EXCEPTIONS
4180 cx->throwing = JS_TRUE;
4181 cx->exception = v;
4182 #endif
4183 }
4185 JS_PUBLIC_API(void)
4186 JS_ClearPendingException(JSContext *cx)
4187 {
4188 #if JS_HAS_EXCEPTIONS
4189 cx->throwing = JS_FALSE;
4190 cx->exception = JSVAL_VOID;
4191 #endif
4192 }
4194 JS_PUBLIC_API(JSBool)
4195 JS_ReportPendingException(JSContext *cx)
4196 {
4197 #if JS_HAS_EXCEPTIONS
4198 CHECK_REQUEST(cx);
4199 return js_ReportUncaughtException(cx);
4200 #else
4201 return JS_TRUE;
4202 #endif
4203 }
4205 #if JS_HAS_EXCEPTIONS
4206 struct JSExceptionState {
4207 JSBool throwing;
4208 jsval exception;
4209 };
4210 #endif
4212 JS_PUBLIC_API(JSExceptionState *)
4213 JS_SaveExceptionState(JSContext *cx)
4214 {
4215 #if JS_HAS_EXCEPTIONS
4216 JSExceptionState *state;
4218 CHECK_REQUEST(cx);
4219 state = (JSExceptionState *) JS_malloc(cx, sizeof(JSExceptionState));
4220 if (state) {
4221 state->throwing = JS_GetPendingException(cx, &state->exception);
4222 if (state->throwing && JSVAL_IS_GCTHING(state->exception))
4223 js_AddRoot(cx, &state->exception, "JSExceptionState.exception");
4224 }
4225 return state;
4226 #else
4227 return NULL;
4228 #endif
4229 }
4231 JS_PUBLIC_API(void)
4232 JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state)
4233 {
4234 #if JS_HAS_EXCEPTIONS
4235 CHECK_REQUEST(cx);
4236 if (state) {
4237 if (state->throwing)
4238 JS_SetPendingException(cx, state->exception);
4239 else
4240 JS_ClearPendingException(cx);
4241 JS_DropExceptionState(cx, state);
4242 }
4243 #endif
4244 }
4246 JS_PUBLIC_API(void)
4247 JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
4248 {
4249 #if JS_HAS_EXCEPTIONS
4250 CHECK_REQUEST(cx);
4251 if (state) {
4252 if (state->throwing && JSVAL_IS_GCTHING(state->exception))
4253 JS_RemoveRoot(cx, &state->exception);
4254 JS_free(cx, state);
4255 }
4256 #endif
4257 }
4259 JS_PUBLIC_API(JSErrorReport *)
4260 JS_ErrorFromException(JSContext *cx, jsval v)
4261 {
4262 #if JS_HAS_EXCEPTIONS
4263 CHECK_REQUEST(cx);
4264 return js_ErrorFromException(cx, v);
4265 #else
4266 return NULL;
4267 #endif
4268 }
4270 #ifdef JS_THREADSAFE
4271 JS_PUBLIC_API(jsword)
4272 JS_GetContextThread(JSContext *cx)
4273 {
4274 return cx->thread;
4275 }
4277 JS_PUBLIC_API(jsword)
4278 JS_SetContextThread(JSContext *cx)
4279 {
4280 jsword old = cx->thread;
4281 cx->thread = js_CurrentThreadId();
4282 return old;
4283 }
4285 JS_PUBLIC_API(jsword)
4286 JS_ClearContextThread(JSContext *cx)
4287 {
4288 jsword old = cx->thread;
4289 cx->thread = 0;
4290 return old;
4291 }
4292 #endif
4294 /************************************************************************/
4296 #if defined(XP_WIN)
4297 #include <windows.h>
4298 /*
4299 * Initialization routine for the JS DLL...
4300 */
4302 /*
4303 * Global Instance handle...
4304 * In Win32 this is the module handle of the DLL.
4305 *
4306 * In Win16 this is the instance handle of the application
4307 * which loaded the DLL.
4308 */
4310 #ifdef _WIN32
4311 BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
4312 {
4313 return TRUE;
4314 }
4316 #else /* !_WIN32 */
4318 int CALLBACK LibMain( HINSTANCE hInst, WORD wDataSeg,
4319 WORD cbHeapSize, LPSTR lpszCmdLine )
4320 {
4321 return TRUE;
4322 }
4324 BOOL CALLBACK __loadds WEP(BOOL fSystemExit)
4325 {
4326 return TRUE;
4327 }
4329 #endif /* !_WIN32 */
4330 #endif /* XP_WIN */