Parent Directory
|
Revision Log
Upgrade to SpiderMonkey from Firefox 3.5.3.
1 | siliconforks | 332 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 | * vim: set ts=8 sw=4 et tw=78: | ||
3 | * | ||
4 | * ***** BEGIN LICENSE BLOCK ***** | ||
5 | * Version: MPL 1.1/GPL 2.0/LGPL 2.1 | ||
6 | * | ||
7 | * The contents of this file are subject to the Mozilla Public License Version | ||
8 | * 1.1 (the "License"); you may not use this file except in compliance with | ||
9 | * the License. You may obtain a copy of the License at | ||
10 | * http://www.mozilla.org/MPL/ | ||
11 | * | ||
12 | * Software distributed under the License is distributed on an "AS IS" basis, | ||
13 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | ||
14 | * for the specific language governing rights and limitations under the | ||
15 | * License. | ||
16 | * | ||
17 | * The Original Code is Mozilla Communicator client code, released | ||
18 | * March 31, 1998. | ||
19 | * | ||
20 | * The Initial Developer of the Original Code is | ||
21 | * Netscape Communications Corporation. | ||
22 | * Portions created by the Initial Developer are Copyright (C) 1998 | ||
23 | * the Initial Developer. All Rights Reserved. | ||
24 | * | ||
25 | * Contributor(s): | ||
26 | * | ||
27 | * Alternatively, the contents of this file may be used under the terms of | ||
28 | * either of the GNU General Public License Version 2 or later (the "GPL"), | ||
29 | * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), | ||
30 | * in which case the provisions of the GPL or the LGPL are applicable instead | ||
31 | * of those above. If you wish to allow use of your version of this file only | ||
32 | * under the terms of either the GPL or the LGPL, and not to allow others to | ||
33 | * use your version of this file under the terms of the MPL, indicate your | ||
34 | * decision by deleting the provisions above and replace them with the notice | ||
35 | * and other provisions required by the GPL or the LGPL. If you do not delete | ||
36 | * the provisions above, a recipient may use your version of this file under | ||
37 | * the terms of any one of the MPL, the GPL or the LGPL. | ||
38 | * | ||
39 | * ***** END LICENSE BLOCK ***** */ | ||
40 | |||
41 | /* | ||
42 | * JavaScript API. | ||
43 | */ | ||
44 | #include "jsstddef.h" | ||
45 | #include <ctype.h> | ||
46 | #include <stdarg.h> | ||
47 | #include <stdlib.h> | ||
48 | #include <string.h> | ||
49 | #include "jstypes.h" | ||
50 | #include "jsarena.h" /* Added by JSIFY */ | ||
51 | #include "jsutil.h" /* Added by JSIFY */ | ||
52 | #include "jsclist.h" | ||
53 | #include "jsdhash.h" | ||
54 | #include "jsprf.h" | ||
55 | #include "jsapi.h" | ||
56 | #include "jsarray.h" | ||
57 | #include "jsatom.h" | ||
58 | #include "jsbool.h" | ||
59 | siliconforks | 399 | #include "jsbuiltins.h" |
60 | siliconforks | 332 | #include "jscntxt.h" |
61 | #include "jsversion.h" | ||
62 | #include "jsdate.h" | ||
63 | #include "jsdtoa.h" | ||
64 | #include "jsemit.h" | ||
65 | #include "jsexn.h" | ||
66 | #include "jsfun.h" | ||
67 | #include "jsgc.h" | ||
68 | #include "jsinterp.h" | ||
69 | #include "jsiter.h" | ||
70 | #include "jslock.h" | ||
71 | #include "jsmath.h" | ||
72 | #include "jsnum.h" | ||
73 | #include "json.h" | ||
74 | #include "jsobj.h" | ||
75 | #include "jsopcode.h" | ||
76 | #include "jsparse.h" | ||
77 | #include "jsregexp.h" | ||
78 | #include "jsscan.h" | ||
79 | #include "jsscope.h" | ||
80 | #include "jsscript.h" | ||
81 | #include "jsstr.h" | ||
82 | siliconforks | 460 | #include "jstracer.h" |
83 | #include "jsdbgapi.h" | ||
84 | siliconforks | 332 | #include "prmjtime.h" |
85 | #include "jsstaticcheck.h" | ||
86 | |||
87 | #if JS_HAS_FILE_OBJECT | ||
88 | #include "jsfile.h" | ||
89 | #endif | ||
90 | |||
91 | #if JS_HAS_XML_SUPPORT | ||
92 | #include "jsxml.h" | ||
93 | #endif | ||
94 | |||
95 | #ifdef HAVE_VA_LIST_AS_ARRAY | ||
96 | #define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap)) | ||
97 | #else | ||
98 | #define JS_ADDRESSOF_VA_LIST(ap) (&(ap)) | ||
99 | #endif | ||
100 | |||
101 | #if defined(JS_THREADSAFE) | ||
102 | #define CHECK_REQUEST(cx) \ | ||
103 | JS_ASSERT((cx)->requestDepth || (cx)->thread == (cx)->runtime->gcThread) | ||
104 | #else | ||
105 | #define CHECK_REQUEST(cx) ((void)0) | ||
106 | #endif | ||
107 | |||
108 | siliconforks | 460 | /* Check that we can cast JSObject* as jsval without tag bit manipulations. */ |
109 | JS_STATIC_ASSERT(JSVAL_OBJECT == 0); | ||
110 | |||
111 | /* Check that JSVAL_TRACE_KIND works. */ | ||
112 | JS_STATIC_ASSERT(JSVAL_TRACE_KIND(JSVAL_OBJECT) == JSTRACE_OBJECT); | ||
113 | JS_STATIC_ASSERT(JSVAL_TRACE_KIND(JSVAL_DOUBLE) == JSTRACE_DOUBLE); | ||
114 | JS_STATIC_ASSERT(JSVAL_TRACE_KIND(JSVAL_STRING) == JSTRACE_STRING); | ||
115 | |||
116 | siliconforks | 332 | JS_PUBLIC_API(int64) |
117 | JS_Now() | ||
118 | { | ||
119 | return PRMJ_Now(); | ||
120 | } | ||
121 | |||
122 | JS_PUBLIC_API(jsval) | ||
123 | JS_GetNaNValue(JSContext *cx) | ||
124 | { | ||
125 | return DOUBLE_TO_JSVAL(cx->runtime->jsNaN); | ||
126 | } | ||
127 | |||
128 | JS_PUBLIC_API(jsval) | ||
129 | JS_GetNegativeInfinityValue(JSContext *cx) | ||
130 | { | ||
131 | return DOUBLE_TO_JSVAL(cx->runtime->jsNegativeInfinity); | ||
132 | } | ||
133 | |||
134 | JS_PUBLIC_API(jsval) | ||
135 | JS_GetPositiveInfinityValue(JSContext *cx) | ||
136 | { | ||
137 | return DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity); | ||
138 | } | ||
139 | |||
140 | JS_PUBLIC_API(jsval) | ||
141 | JS_GetEmptyStringValue(JSContext *cx) | ||
142 | { | ||
143 | return STRING_TO_JSVAL(cx->runtime->emptyString); | ||
144 | } | ||
145 | |||
146 | static JSBool | ||
147 | TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS, | ||
148 | jsval **vpp, va_list *app) | ||
149 | { | ||
150 | const char *format; | ||
151 | JSArgumentFormatMap *map; | ||
152 | |||
153 | format = *formatp; | ||
154 | for (map = cx->argumentFormatMap; map; map = map->next) { | ||
155 | if (!strncmp(format, map->format, map->length)) { | ||
156 | *formatp = format + map->length; | ||
157 | return map->formatter(cx, format, fromJS, vpp, app); | ||
158 | } | ||
159 | } | ||
160 | JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format); | ||
161 | return JS_FALSE; | ||
162 | } | ||
163 | |||
164 | JS_PUBLIC_API(JSBool) | ||
165 | JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format, | ||
166 | ...) | ||
167 | { | ||
168 | va_list ap; | ||
169 | JSBool ok; | ||
170 | |||
171 | va_start(ap, format); | ||
172 | ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap); | ||
173 | va_end(ap); | ||
174 | return ok; | ||
175 | } | ||
176 | |||
177 | JS_PUBLIC_API(JSBool) | ||
178 | JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv, | ||
179 | const char *format, va_list ap) | ||
180 | { | ||
181 | jsval *sp; | ||
182 | JSBool required; | ||
183 | char c; | ||
184 | JSFunction *fun; | ||
185 | jsdouble d; | ||
186 | JSString *str; | ||
187 | JSObject *obj; | ||
188 | |||
189 | CHECK_REQUEST(cx); | ||
190 | sp = argv; | ||
191 | required = JS_TRUE; | ||
192 | while ((c = *format++) != '\0') { | ||
193 | if (isspace(c)) | ||
194 | continue; | ||
195 | if (c == '/') { | ||
196 | required = JS_FALSE; | ||
197 | continue; | ||
198 | } | ||
199 | if (sp == argv + argc) { | ||
200 | if (required) { | ||
201 | fun = js_ValueToFunction(cx, &argv[-2], 0); | ||
202 | if (fun) { | ||
203 | char numBuf[12]; | ||
204 | JS_snprintf(numBuf, sizeof numBuf, "%u", argc); | ||
205 | JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, | ||
206 | JSMSG_MORE_ARGS_NEEDED, | ||
207 | JS_GetFunctionName(fun), numBuf, | ||
208 | (argc == 1) ? "" : "s"); | ||
209 | } | ||
210 | return JS_FALSE; | ||
211 | } | ||
212 | break; | ||
213 | } | ||
214 | switch (c) { | ||
215 | case 'b': | ||
216 | *va_arg(ap, JSBool *) = js_ValueToBoolean(*sp); | ||
217 | break; | ||
218 | case 'c': | ||
219 | if (!JS_ValueToUint16(cx, *sp, va_arg(ap, uint16 *))) | ||
220 | return JS_FALSE; | ||
221 | break; | ||
222 | case 'i': | ||
223 | if (!JS_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *))) | ||
224 | return JS_FALSE; | ||
225 | break; | ||
226 | case 'u': | ||
227 | if (!JS_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *))) | ||
228 | return JS_FALSE; | ||
229 | break; | ||
230 | case 'j': | ||
231 | if (!JS_ValueToInt32(cx, *sp, va_arg(ap, int32 *))) | ||
232 | return JS_FALSE; | ||
233 | break; | ||
234 | case 'd': | ||
235 | if (!JS_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *))) | ||
236 | return JS_FALSE; | ||
237 | break; | ||
238 | case 'I': | ||
239 | if (!JS_ValueToNumber(cx, *sp, &d)) | ||
240 | return JS_FALSE; | ||
241 | *va_arg(ap, jsdouble *) = js_DoubleToInteger(d); | ||
242 | break; | ||
243 | case 's': | ||
244 | case 'S': | ||
245 | case 'W': | ||
246 | str = js_ValueToString(cx, *sp); | ||
247 | if (!str) | ||
248 | return JS_FALSE; | ||
249 | *sp = STRING_TO_JSVAL(str); | ||
250 | if (c == 's') { | ||
251 | const char *bytes = js_GetStringBytes(cx, str); | ||
252 | if (!bytes) | ||
253 | return JS_FALSE; | ||
254 | *va_arg(ap, const char **) = bytes; | ||
255 | } else if (c == 'W') { | ||
256 | const jschar *chars = js_GetStringChars(cx, str); | ||
257 | if (!chars) | ||
258 | return JS_FALSE; | ||
259 | *va_arg(ap, const jschar **) = chars; | ||
260 | } else { | ||
261 | *va_arg(ap, JSString **) = str; | ||
262 | } | ||
263 | break; | ||
264 | case 'o': | ||
265 | if (!js_ValueToObject(cx, *sp, &obj)) | ||
266 | return JS_FALSE; | ||
267 | *sp = OBJECT_TO_JSVAL(obj); | ||
268 | *va_arg(ap, JSObject **) = obj; | ||
269 | break; | ||
270 | case 'f': | ||
271 | obj = js_ValueToFunctionObject(cx, sp, 0); | ||
272 | if (!obj) | ||
273 | return JS_FALSE; | ||
274 | *sp = OBJECT_TO_JSVAL(obj); | ||
275 | *va_arg(ap, JSFunction **) = (JSFunction *) JS_GetPrivate(cx, obj); | ||
276 | break; | ||
277 | case 'v': | ||
278 | *va_arg(ap, jsval *) = *sp; | ||
279 | break; | ||
280 | case '*': | ||
281 | break; | ||
282 | default: | ||
283 | format--; | ||
284 | if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp, | ||
285 | JS_ADDRESSOF_VA_LIST(ap))) { | ||
286 | return JS_FALSE; | ||
287 | } | ||
288 | /* NB: the formatter already updated sp, so we continue here. */ | ||
289 | continue; | ||
290 | } | ||
291 | sp++; | ||
292 | } | ||
293 | return JS_TRUE; | ||
294 | } | ||
295 | |||
296 | JS_PUBLIC_API(jsval *) | ||
297 | JS_PushArguments(JSContext *cx, void **markp, const char *format, ...) | ||
298 | { | ||
299 | va_list ap; | ||
300 | jsval *argv; | ||
301 | |||
302 | va_start(ap, format); | ||
303 | argv = JS_PushArgumentsVA(cx, markp, format, ap); | ||
304 | va_end(ap); | ||
305 | return argv; | ||
306 | } | ||
307 | |||
308 | JS_PUBLIC_API(jsval *) | ||
309 | JS_PushArgumentsVA(JSContext *cx, void **markp, const char *format, va_list ap) | ||
310 | { | ||
311 | uintN argc; | ||
312 | jsval *argv, *sp; | ||
313 | char c; | ||
314 | const char *cp; | ||
315 | JSString *str; | ||
316 | JSFunction *fun; | ||
317 | JSStackHeader *sh; | ||
318 | |||
319 | CHECK_REQUEST(cx); | ||
320 | *markp = NULL; | ||
321 | argc = 0; | ||
322 | for (cp = format; (c = *cp) != '\0'; cp++) { | ||
323 | /* | ||
324 | * Count non-space non-star characters as individual jsval arguments. | ||
325 | * This may over-allocate stack, but we'll fix below. | ||
326 | */ | ||
327 | if (isspace(c) || c == '*') | ||
328 | continue; | ||
329 | argc++; | ||
330 | } | ||
331 | siliconforks | 460 | js_LeaveTrace(cx); |
332 | siliconforks | 332 | sp = js_AllocStack(cx, argc, markp); |
333 | if (!sp) | ||
334 | return NULL; | ||
335 | argv = sp; | ||
336 | while ((c = *format++) != '\0') { | ||
337 | if (isspace(c) || c == '*') | ||
338 | continue; | ||
339 | switch (c) { | ||
340 | case 'b': | ||
341 | *sp = BOOLEAN_TO_JSVAL((JSBool) va_arg(ap, int)); | ||
342 | break; | ||
343 | case 'c': | ||
344 | *sp = INT_TO_JSVAL((uint16) va_arg(ap, unsigned int)); | ||
345 | break; | ||
346 | case 'i': | ||
347 | case 'j': | ||
348 | /* | ||
349 | * Use JS_New{Double,Number}Value here and in the next two cases, | ||
350 | * not js_New{Double,Number}InRootedValue, as sp may point to an | ||
351 | * unrooted location. | ||
352 | */ | ||
353 | if (!JS_NewNumberValue(cx, (jsdouble) va_arg(ap, int32), sp)) | ||
354 | goto bad; | ||
355 | break; | ||
356 | case 'u': | ||
357 | if (!JS_NewNumberValue(cx, (jsdouble) va_arg(ap, uint32), sp)) | ||
358 | goto bad; | ||
359 | break; | ||
360 | case 'd': | ||
361 | case 'I': | ||
362 | if (!JS_NewDoubleValue(cx, va_arg(ap, jsdouble), sp)) | ||
363 | goto bad; | ||
364 | break; | ||
365 | case 's': | ||
366 | str = JS_NewStringCopyZ(cx, va_arg(ap, char *)); | ||
367 | if (!str) | ||
368 | goto bad; | ||
369 | *sp = STRING_TO_JSVAL(str); | ||
370 | break; | ||
371 | case 'W': | ||
372 | str = JS_NewUCStringCopyZ(cx, va_arg(ap, jschar *)); | ||
373 | if (!str) | ||
374 | goto bad; | ||
375 | *sp = STRING_TO_JSVAL(str); | ||
376 | break; | ||
377 | case 'S': | ||
378 | str = va_arg(ap, JSString *); | ||
379 | *sp = STRING_TO_JSVAL(str); | ||
380 | break; | ||
381 | case 'o': | ||
382 | *sp = OBJECT_TO_JSVAL(va_arg(ap, JSObject *)); | ||
383 | break; | ||
384 | case 'f': | ||
385 | fun = va_arg(ap, JSFunction *); | ||
386 | *sp = fun ? OBJECT_TO_JSVAL(FUN_OBJECT(fun)) : JSVAL_NULL; | ||
387 | break; | ||
388 | case 'v': | ||
389 | *sp = va_arg(ap, jsval); | ||
390 | break; | ||
391 | default: | ||
392 | format--; | ||
393 | if (!TryArgumentFormatter(cx, &format, JS_FALSE, &sp, | ||
394 | JS_ADDRESSOF_VA_LIST(ap))) { | ||
395 | goto bad; | ||
396 | } | ||
397 | /* NB: the formatter already updated sp, so we continue here. */ | ||
398 | continue; | ||
399 | } | ||
400 | sp++; | ||
401 | } | ||
402 | |||
403 | /* | ||
404 | * We may have overallocated stack due to a multi-character format code | ||
405 | * handled by a JSArgumentFormatter. Give back that stack space! | ||
406 | */ | ||
407 | JS_ASSERT(sp <= argv + argc); | ||
408 | if (sp < argv + argc) { | ||
409 | /* Return slots not pushed to the current stack arena. */ | ||
410 | cx->stackPool.current->avail = (jsuword)sp; | ||
411 | |||
412 | /* Reduce the count of slots the GC will scan in this stack segment. */ | ||
413 | sh = cx->stackHeaders; | ||
414 | JS_ASSERT(JS_STACK_SEGMENT(sh) + sh->nslots == argv + argc); | ||
415 | sh->nslots -= argc - (sp - argv); | ||
416 | } | ||
417 | return argv; | ||
418 | |||
419 | bad: | ||
420 | js_FreeStack(cx, *markp); | ||
421 | return NULL; | ||
422 | } | ||
423 | |||
424 | JS_PUBLIC_API(void) | ||
425 | JS_PopArguments(JSContext *cx, void *mark) | ||
426 | { | ||
427 | CHECK_REQUEST(cx); | ||
428 | siliconforks | 460 | JS_ASSERT_NOT_ON_TRACE(cx); |
429 | siliconforks | 332 | js_FreeStack(cx, mark); |
430 | } | ||
431 | |||
432 | JS_PUBLIC_API(JSBool) | ||
433 | JS_AddArgumentFormatter(JSContext *cx, const char *format, | ||
434 | JSArgumentFormatter formatter) | ||
435 | { | ||
436 | size_t length; | ||
437 | JSArgumentFormatMap **mpp, *map; | ||
438 | |||
439 | length = strlen(format); | ||
440 | mpp = &cx->argumentFormatMap; | ||
441 | while ((map = *mpp) != NULL) { | ||
442 | /* Insert before any shorter string to match before prefixes. */ | ||
443 | if (map->length < length) | ||
444 | break; | ||
445 | if (map->length == length && !strcmp(map->format, format)) | ||
446 | goto out; | ||
447 | mpp = &map->next; | ||
448 | } | ||
449 | map = (JSArgumentFormatMap *) JS_malloc(cx, sizeof *map); | ||
450 | if (!map) | ||
451 | return JS_FALSE; | ||
452 | map->format = format; | ||
453 | map->length = length; | ||
454 | map->next = *mpp; | ||
455 | *mpp = map; | ||
456 | out: | ||
457 | map->formatter = formatter; | ||
458 | return JS_TRUE; | ||
459 | } | ||
460 | |||
461 | JS_PUBLIC_API(void) | ||
462 | JS_RemoveArgumentFormatter(JSContext *cx, const char *format) | ||
463 | { | ||
464 | size_t length; | ||
465 | JSArgumentFormatMap **mpp, *map; | ||
466 | |||
467 | length = strlen(format); | ||
468 | mpp = &cx->argumentFormatMap; | ||
469 | while ((map = *mpp) != NULL) { | ||
470 | if (map->length == length && !strcmp(map->format, format)) { | ||
471 | *mpp = map->next; | ||
472 | JS_free(cx, map); | ||
473 | return; | ||
474 | } | ||
475 | mpp = &map->next; | ||
476 | } | ||
477 | } | ||
478 | |||
479 | JS_PUBLIC_API(JSBool) | ||
480 | JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp) | ||
481 | { | ||
482 | JSBool ok; | ||
483 | JSObject *obj; | ||
484 | JSString *str; | ||
485 | jsdouble d, *dp; | ||
486 | |||
487 | CHECK_REQUEST(cx); | ||
488 | switch (type) { | ||
489 | case JSTYPE_VOID: | ||
490 | *vp = JSVAL_VOID; | ||
491 | ok = JS_TRUE; | ||
492 | break; | ||
493 | case JSTYPE_OBJECT: | ||
494 | ok = js_ValueToObject(cx, v, &obj); | ||
495 | if (ok) | ||
496 | *vp = OBJECT_TO_JSVAL(obj); | ||
497 | break; | ||
498 | case JSTYPE_FUNCTION: | ||
499 | *vp = v; | ||
500 | obj = js_ValueToFunctionObject(cx, vp, JSV2F_SEARCH_STACK); | ||
501 | ok = (obj != NULL); | ||
502 | break; | ||
503 | case JSTYPE_STRING: | ||
504 | str = js_ValueToString(cx, v); | ||
505 | ok = (str != NULL); | ||
506 | if (ok) | ||
507 | *vp = STRING_TO_JSVAL(str); | ||
508 | break; | ||
509 | case JSTYPE_NUMBER: | ||
510 | ok = JS_ValueToNumber(cx, v, &d); | ||
511 | if (ok) { | ||
512 | dp = js_NewWeaklyRootedDouble(cx, d); | ||
513 | ok = (dp != NULL); | ||
514 | if (ok) | ||
515 | *vp = DOUBLE_TO_JSVAL(dp); | ||
516 | } | ||
517 | break; | ||
518 | case JSTYPE_BOOLEAN: | ||
519 | *vp = BOOLEAN_TO_JSVAL(js_ValueToBoolean(v)); | ||
520 | return JS_TRUE; | ||
521 | default: { | ||
522 | char numBuf[12]; | ||
523 | JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type); | ||
524 | JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE, | ||
525 | numBuf); | ||
526 | ok = JS_FALSE; | ||
527 | break; | ||
528 | } | ||
529 | } | ||
530 | return ok; | ||
531 | } | ||
532 | |||
533 | JS_PUBLIC_API(JSBool) | ||
534 | JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp) | ||
535 | { | ||
536 | CHECK_REQUEST(cx); | ||
537 | return js_ValueToObject(cx, v, objp); | ||
538 | } | ||
539 | |||
540 | JS_PUBLIC_API(JSFunction *) | ||
541 | JS_ValueToFunction(JSContext *cx, jsval v) | ||
542 | { | ||
543 | CHECK_REQUEST(cx); | ||
544 | return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK); | ||
545 | } | ||
546 | |||
547 | JS_PUBLIC_API(JSFunction *) | ||
548 | JS_ValueToConstructor(JSContext *cx, jsval v) | ||
549 | { | ||
550 | CHECK_REQUEST(cx); | ||
551 | return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK); | ||
552 | } | ||
553 | |||
554 | JS_PUBLIC_API(JSString *) | ||
555 | JS_ValueToString(JSContext *cx, jsval v) | ||
556 | { | ||
557 | CHECK_REQUEST(cx); | ||
558 | return js_ValueToString(cx, v); | ||
559 | } | ||
560 | |||
561 | siliconforks | 399 | JS_PUBLIC_API(JSString *) |
562 | JS_ValueToSource(JSContext *cx, jsval v) | ||
563 | { | ||
564 | CHECK_REQUEST(cx); | ||
565 | return js_ValueToSource(cx, v); | ||
566 | } | ||
567 | |||
568 | siliconforks | 332 | JS_PUBLIC_API(JSBool) |
569 | JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp) | ||
570 | { | ||
571 | JSTempValueRooter tvr; | ||
572 | |||
573 | CHECK_REQUEST(cx); | ||
574 | JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr); | ||
575 | *dp = js_ValueToNumber(cx, &tvr.u.value); | ||
576 | JS_POP_TEMP_ROOT(cx, &tvr); | ||
577 | return !JSVAL_IS_NULL(tvr.u.value); | ||
578 | } | ||
579 | |||
580 | JS_PUBLIC_API(JSBool) | ||
581 | JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip) | ||
582 | { | ||
583 | JSTempValueRooter tvr; | ||
584 | |||
585 | CHECK_REQUEST(cx); | ||
586 | JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr); | ||
587 | *ip = js_ValueToECMAInt32(cx, &tvr.u.value); | ||
588 | JS_POP_TEMP_ROOT(cx, &tvr); | ||
589 | return !JSVAL_IS_NULL(tvr.u.value); | ||
590 | } | ||
591 | |||
592 | JS_PUBLIC_API(JSBool) | ||
593 | JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip) | ||
594 | { | ||
595 | JSTempValueRooter tvr; | ||
596 | |||
597 | CHECK_REQUEST(cx); | ||
598 | JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr); | ||
599 | *ip = js_ValueToECMAUint32(cx, &tvr.u.value); | ||
600 | JS_POP_TEMP_ROOT(cx, &tvr); | ||
601 | return !JSVAL_IS_NULL(tvr.u.value); | ||
602 | } | ||
603 | |||
604 | JS_PUBLIC_API(JSBool) | ||
605 | JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip) | ||
606 | { | ||
607 | JSTempValueRooter tvr; | ||
608 | |||
609 | CHECK_REQUEST(cx); | ||
610 | JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr); | ||
611 | *ip = js_ValueToInt32(cx, &tvr.u.value); | ||
612 | JS_POP_TEMP_ROOT(cx, &tvr); | ||
613 | return !JSVAL_IS_NULL(tvr.u.value); | ||
614 | } | ||
615 | |||
616 | JS_PUBLIC_API(JSBool) | ||
617 | JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip) | ||
618 | { | ||
619 | JSTempValueRooter tvr; | ||
620 | |||
621 | CHECK_REQUEST(cx); | ||
622 | JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr); | ||
623 | *ip = js_ValueToUint16(cx, &tvr.u.value); | ||
624 | JS_POP_TEMP_ROOT(cx, &tvr); | ||
625 | return !JSVAL_IS_NULL(tvr.u.value); | ||
626 | } | ||
627 | |||
628 | JS_PUBLIC_API(JSBool) | ||
629 | JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp) | ||
630 | { | ||
631 | CHECK_REQUEST(cx); | ||
632 | *bp = js_ValueToBoolean(v); | ||
633 | return JS_TRUE; | ||
634 | } | ||
635 | |||
636 | JS_PUBLIC_API(JSType) | ||
637 | JS_TypeOfValue(JSContext *cx, jsval v) | ||
638 | { | ||
639 | JSType type; | ||
640 | JSObject *obj; | ||
641 | JSObjectOps *ops; | ||
642 | JSClass *clasp; | ||
643 | |||
644 | CHECK_REQUEST(cx); | ||
645 | if (JSVAL_IS_OBJECT(v)) { | ||
646 | type = JSTYPE_OBJECT; /* XXXbe JSTYPE_NULL for JS2 */ | ||
647 | obj = JSVAL_TO_OBJECT(v); | ||
648 | if (obj) { | ||
649 | siliconforks | 460 | obj = js_GetWrappedObject(cx, obj); |
650 | siliconforks | 332 | |
651 | ops = obj->map->ops; | ||
652 | #if JS_HAS_XML_SUPPORT | ||
653 | siliconforks | 460 | if (ops == &js_XMLObjectOps) { |
654 | siliconforks | 332 | type = JSTYPE_XML; |
655 | } else | ||
656 | #endif | ||
657 | { | ||
658 | /* | ||
659 | * ECMA 262, 11.4.3 says that any native object that implements | ||
660 | siliconforks | 460 | * [[Call]] should be of type "function". However, RegExp is of |
661 | * type "object", not "function", for Web compatibility. | ||
662 | siliconforks | 332 | */ |
663 | clasp = OBJ_GET_CLASS(cx, obj); | ||
664 | if ((ops == &js_ObjectOps) | ||
665 | ? (clasp->call | ||
666 | ? clasp == &js_ScriptClass | ||
667 | : clasp == &js_FunctionClass) | ||
668 | : ops->call != NULL) { | ||
669 | type = JSTYPE_FUNCTION; | ||
670 | } else { | ||
671 | #ifdef NARCISSUS | ||
672 | JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); | ||
673 | |||
674 | if (!OBJ_GET_PROPERTY(cx, obj, | ||
675 | ATOM_TO_JSID(cx->runtime->atomState | ||
676 | siliconforks | 399 | .__call__Atom), |
677 | siliconforks | 332 | &v)) { |
678 | JS_ClearPendingException(cx); | ||
679 | } else if (VALUE_IS_FUNCTION(cx, v)) { | ||
680 | type = JSTYPE_FUNCTION; | ||
681 | } | ||
682 | #endif | ||
683 | } | ||
684 | } | ||
685 | } | ||
686 | } else if (JSVAL_IS_NUMBER(v)) { | ||
687 | type = JSTYPE_NUMBER; | ||
688 | } else if (JSVAL_IS_STRING(v)) { | ||
689 | type = JSTYPE_STRING; | ||
690 | } else if (JSVAL_IS_BOOLEAN(v)) { | ||
691 | type = JSTYPE_BOOLEAN; | ||
692 | } else { | ||
693 | type = JSTYPE_VOID; | ||
694 | } | ||
695 | return type; | ||
696 | } | ||
697 | |||
698 | JS_PUBLIC_API(const char *) | ||
699 | JS_GetTypeName(JSContext *cx, JSType type) | ||
700 | { | ||
701 | if ((uintN)type >= (uintN)JSTYPE_LIMIT) | ||
702 | return NULL; | ||
703 | return JS_TYPE_STR(type); | ||
704 | } | ||
705 | |||
706 | /************************************************************************/ | ||
707 | |||
708 | /* | ||
709 | * Has a new runtime ever been created? This flag is used to detect unsafe | ||
710 | * changes to js_CStringsAreUTF8 after a runtime has been created, and to | ||
711 | * ensure that "first checks" on runtime creation are run only once. | ||
712 | */ | ||
713 | #ifdef DEBUG | ||
714 | static JSBool js_NewRuntimeWasCalled = JS_FALSE; | ||
715 | #endif | ||
716 | |||
717 | JS_PUBLIC_API(JSRuntime *) | ||
718 | JS_NewRuntime(uint32 maxbytes) | ||
719 | { | ||
720 | JSRuntime *rt; | ||
721 | |||
722 | #ifdef DEBUG | ||
723 | if (!js_NewRuntimeWasCalled) { | ||
724 | /* | ||
725 | * This code asserts that the numbers associated with the error names | ||
726 | * in jsmsg.def are monotonically increasing. It uses values for the | ||
727 | * error names enumerated in jscntxt.c. It's not a compile-time check | ||
728 | * but it's better than nothing. | ||
729 | */ | ||
730 | int errorNumber = 0; | ||
731 | #define MSG_DEF(name, number, count, exception, format) \ | ||
732 | JS_ASSERT(name == errorNumber++); | ||
733 | #include "js.msg" | ||
734 | #undef MSG_DEF | ||
735 | |||
736 | #define MSG_DEF(name, number, count, exception, format) \ | ||
737 | JS_BEGIN_MACRO \ | ||
738 | uintN numfmtspecs = 0; \ | ||
739 | const char *fmt; \ | ||
740 | for (fmt = format; *fmt != '\0'; fmt++) { \ | ||
741 | if (*fmt == '{' && isdigit(fmt[1])) \ | ||
742 | ++numfmtspecs; \ | ||
743 | } \ | ||
744 | JS_ASSERT(count == numfmtspecs); \ | ||
745 | JS_END_MACRO; | ||
746 | #include "js.msg" | ||
747 | #undef MSG_DEF | ||
748 | |||
749 | siliconforks | 460 | /* |
750 | * If it were possible for pure inline function calls with constant | ||
751 | * arguments to be computed at compile time, these would be static | ||
752 | * assertions, but since it isn't, this is the best we can do. | ||
753 | */ | ||
754 | JS_ASSERT(JSVAL_NULL == OBJECT_TO_JSVAL(NULL)); | ||
755 | JS_ASSERT(JSVAL_ZERO == INT_TO_JSVAL(0)); | ||
756 | JS_ASSERT(JSVAL_ONE == INT_TO_JSVAL(1)); | ||
757 | JS_ASSERT(JSVAL_FALSE == BOOLEAN_TO_JSVAL(JS_FALSE)); | ||
758 | JS_ASSERT(JSVAL_TRUE == BOOLEAN_TO_JSVAL(JS_TRUE)); | ||
759 | |||
760 | JS_ASSERT(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID) == 2); | ||
761 | JS_ASSERT(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_HOLE) == (2 | (JSVAL_HOLE_FLAG >> JSVAL_TAGBITS))); | ||
762 | JS_ASSERT(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_ARETURN) == 8); | ||
763 | |||
764 | siliconforks | 332 | js_NewRuntimeWasCalled = JS_TRUE; |
765 | } | ||
766 | #endif /* DEBUG */ | ||
767 | |||
768 | rt = (JSRuntime *) malloc(sizeof(JSRuntime)); | ||
769 | if (!rt) | ||
770 | return NULL; | ||
771 | |||
772 | /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */ | ||
773 | memset(rt, 0, sizeof(JSRuntime)); | ||
774 | JS_INIT_CLIST(&rt->contextList); | ||
775 | JS_INIT_CLIST(&rt->trapList); | ||
776 | JS_INIT_CLIST(&rt->watchPointList); | ||
777 | |||
778 | if (!js_InitDtoa()) | ||
779 | goto bad; | ||
780 | if (!js_InitGC(rt, maxbytes)) | ||
781 | goto bad; | ||
782 | if (!js_InitAtomState(rt)) | ||
783 | goto bad; | ||
784 | if (!js_InitDeflatedStringCache(rt)) | ||
785 | goto bad; | ||
786 | #ifdef JS_THREADSAFE | ||
787 | rt->gcLock = JS_NEW_LOCK(); | ||
788 | if (!rt->gcLock) | ||
789 | goto bad; | ||
790 | rt->gcDone = JS_NEW_CONDVAR(rt->gcLock); | ||
791 | if (!rt->gcDone) | ||
792 | goto bad; | ||
793 | rt->requestDone = JS_NEW_CONDVAR(rt->gcLock); | ||
794 | if (!rt->requestDone) | ||
795 | goto bad; | ||
796 | /* this is asymmetric with JS_ShutDown: */ | ||
797 | if (!js_SetupLocks(8, 16)) | ||
798 | goto bad; | ||
799 | rt->rtLock = JS_NEW_LOCK(); | ||
800 | if (!rt->rtLock) | ||
801 | goto bad; | ||
802 | rt->stateChange = JS_NEW_CONDVAR(rt->gcLock); | ||
803 | if (!rt->stateChange) | ||
804 | goto bad; | ||
805 | rt->titleSharingDone = JS_NEW_CONDVAR(rt->gcLock); | ||
806 | if (!rt->titleSharingDone) | ||
807 | goto bad; | ||
808 | rt->titleSharingTodo = NO_TITLE_SHARING_TODO; | ||
809 | rt->debuggerLock = JS_NEW_LOCK(); | ||
810 | if (!rt->debuggerLock) | ||
811 | goto bad; | ||
812 | #endif | ||
813 | if (!js_InitPropertyTree(rt)) | ||
814 | goto bad; | ||
815 | siliconforks | 460 | if (!js_InitThreads(rt)) |
816 | goto bad; | ||
817 | siliconforks | 332 | |
818 | return rt; | ||
819 | |||
820 | bad: | ||
821 | JS_DestroyRuntime(rt); | ||
822 | return NULL; | ||
823 | } | ||
824 | |||
825 | JS_PUBLIC_API(void) | ||
826 | JS_DestroyRuntime(JSRuntime *rt) | ||
827 | { | ||
828 | #ifdef DEBUG | ||
829 | /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */ | ||
830 | if (!JS_CLIST_IS_EMPTY(&rt->contextList)) { | ||
831 | JSContext *cx, *iter = NULL; | ||
832 | uintN cxcount = 0; | ||
833 | while ((cx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL) { | ||
834 | fprintf(stderr, | ||
835 | "JS API usage error: found live context at %p\n", | ||
836 | siliconforks | 460 | (void *) cx); |
837 | siliconforks | 332 | cxcount++; |
838 | } | ||
839 | fprintf(stderr, | ||
840 | "JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n", | ||
841 | cxcount, (cxcount == 1) ? "" : "s"); | ||
842 | } | ||
843 | #endif | ||
844 | |||
845 | siliconforks | 460 | js_FinishThreads(rt); |
846 | siliconforks | 332 | js_FreeRuntimeScriptState(rt); |
847 | js_FinishAtomState(rt); | ||
848 | |||
849 | /* | ||
850 | * Free unit string storage only after all strings have been finalized, so | ||
851 | * that js_FinalizeString can detect unit strings and avoid calling free | ||
852 | * on their chars storage. | ||
853 | */ | ||
854 | js_FinishUnitStrings(rt); | ||
855 | |||
856 | /* | ||
857 | * Finish the deflated string cache after the last GC and after | ||
858 | * calling js_FinishAtomState, which finalizes strings. | ||
859 | */ | ||
860 | js_FinishDeflatedStringCache(rt); | ||
861 | js_FinishGC(rt); | ||
862 | #ifdef JS_THREADSAFE | ||
863 | if (rt->gcLock) | ||
864 | JS_DESTROY_LOCK(rt->gcLock); | ||
865 | if (rt->gcDone) | ||
866 | JS_DESTROY_CONDVAR(rt->gcDone); | ||
867 | if (rt->requestDone) | ||
868 | JS_DESTROY_CONDVAR(rt->requestDone); | ||
869 | if (rt->rtLock) | ||
870 | JS_DESTROY_LOCK(rt->rtLock); | ||
871 | if (rt->stateChange) | ||
872 | JS_DESTROY_CONDVAR(rt->stateChange); | ||
873 | if (rt->titleSharingDone) | ||
874 | JS_DESTROY_CONDVAR(rt->titleSharingDone); | ||
875 | if (rt->debuggerLock) | ||
876 | JS_DESTROY_LOCK(rt->debuggerLock); | ||
877 | #endif | ||
878 | js_FinishPropertyTree(rt); | ||
879 | free(rt); | ||
880 | } | ||
881 | |||
882 | JS_PUBLIC_API(void) | ||
883 | JS_ShutDown(void) | ||
884 | { | ||
885 | #ifdef JS_OPMETER | ||
886 | extern void js_DumpOpMeters(); | ||
887 | |||
888 | js_DumpOpMeters(); | ||
889 | #endif | ||
890 | |||
891 | js_FinishDtoa(); | ||
892 | #ifdef JS_THREADSAFE | ||
893 | js_CleanupLocks(); | ||
894 | #endif | ||
895 | PRMJ_NowShutdown(); | ||
896 | } | ||
897 | |||
898 | JS_PUBLIC_API(void *) | ||
899 | JS_GetRuntimePrivate(JSRuntime *rt) | ||
900 | { | ||
901 | return rt->data; | ||
902 | } | ||
903 | |||
904 | JS_PUBLIC_API(void) | ||
905 | JS_SetRuntimePrivate(JSRuntime *rt, void *data) | ||
906 | { | ||
907 | rt->data = data; | ||
908 | } | ||
909 | |||
910 | JS_PUBLIC_API(void) | ||
911 | JS_BeginRequest(JSContext *cx) | ||
912 | { | ||
913 | #ifdef JS_THREADSAFE | ||
914 | JSRuntime *rt; | ||
915 | |||
916 | siliconforks | 460 | JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread)); |
917 | siliconforks | 332 | if (!cx->requestDepth) { |
918 | JS_ASSERT(cx->gcLocalFreeLists == &js_GCEmptyFreeListSet); | ||
919 | |||
920 | /* Wait until the GC is finished. */ | ||
921 | rt = cx->runtime; | ||
922 | JS_LOCK_GC(rt); | ||
923 | |||
924 | if (rt->gcThread != cx->thread) { | ||
925 | while (rt->gcLevel > 0) | ||
926 | JS_AWAIT_GC_DONE(rt); | ||
927 | } | ||
928 | |||
929 | /* Indicate that a request is running. */ | ||
930 | rt->requestCount++; | ||
931 | cx->requestDepth = 1; | ||
932 | cx->outstandingRequests++; | ||
933 | JS_UNLOCK_GC(rt); | ||
934 | return; | ||
935 | } | ||
936 | cx->requestDepth++; | ||
937 | cx->outstandingRequests++; | ||
938 | #endif | ||
939 | } | ||
940 | |||
941 | JS_PUBLIC_API(void) | ||
942 | JS_EndRequest(JSContext *cx) | ||
943 | { | ||
944 | #ifdef JS_THREADSAFE | ||
945 | JSRuntime *rt; | ||
946 | |||
947 | CHECK_REQUEST(cx); | ||
948 | siliconforks | 460 | JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread)); |
949 | siliconforks | 332 | JS_ASSERT(cx->requestDepth > 0); |
950 | JS_ASSERT(cx->outstandingRequests > 0); | ||
951 | if (cx->requestDepth == 1) { | ||
952 | siliconforks | 460 | js_LeaveTrace(cx); /* for GC safety */ |
953 | |||
954 | siliconforks | 332 | /* Lock before clearing to interlock with ClaimScope, in jslock.c. */ |
955 | rt = cx->runtime; | ||
956 | JS_LOCK_GC(rt); | ||
957 | cx->requestDepth = 0; | ||
958 | cx->outstandingRequests--; | ||
959 | |||
960 | siliconforks | 460 | js_ShareWaitingTitles(cx); |
961 | siliconforks | 332 | js_RevokeGCLocalFreeLists(cx); |
962 | |||
963 | /* Give the GC a chance to run if this was the last request running. */ | ||
964 | JS_ASSERT(rt->requestCount > 0); | ||
965 | rt->requestCount--; | ||
966 | if (rt->requestCount == 0) | ||
967 | JS_NOTIFY_REQUEST_DONE(rt); | ||
968 | |||
969 | JS_UNLOCK_GC(rt); | ||
970 | return; | ||
971 | } | ||
972 | |||
973 | cx->requestDepth--; | ||
974 | cx->outstandingRequests--; | ||
975 | #endif | ||
976 | } | ||
977 | |||
978 | /* Yield to pending GC operations, regardless of request depth */ | ||
979 | JS_PUBLIC_API(void) | ||
980 | JS_YieldRequest(JSContext *cx) | ||
981 | { | ||
982 | #ifdef JS_THREADSAFE | ||
983 | JS_ASSERT(cx->thread); | ||
984 | CHECK_REQUEST(cx); | ||
985 | JS_ResumeRequest(cx, JS_SuspendRequest(cx)); | ||
986 | #endif | ||
987 | } | ||
988 | |||
989 | JS_PUBLIC_API(jsrefcount) | ||
990 | JS_SuspendRequest(JSContext *cx) | ||
991 | { | ||
992 | #ifdef JS_THREADSAFE | ||
993 | jsrefcount saveDepth = cx->requestDepth; | ||
994 | |||
995 | while (cx->requestDepth) { | ||
996 | cx->outstandingRequests++; /* compensate for JS_EndRequest */ | ||
997 | JS_EndRequest(cx); | ||
998 | } | ||
999 | return saveDepth; | ||
1000 | #else | ||
1001 | return 0; | ||
1002 | #endif | ||
1003 | } | ||
1004 | |||
1005 | JS_PUBLIC_API(void) | ||
1006 | JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth) | ||
1007 | { | ||
1008 | #ifdef JS_THREADSAFE | ||
1009 | JS_ASSERT(!cx->requestDepth); | ||
1010 | while (--saveDepth >= 0) { | ||
1011 | JS_BeginRequest(cx); | ||
1012 | cx->outstandingRequests--; /* compensate for JS_BeginRequest */ | ||
1013 | } | ||
1014 | #endif | ||
1015 | } | ||
1016 | |||
1017 | JS_PUBLIC_API(void) | ||
1018 | JS_Lock(JSRuntime *rt) | ||
1019 | { | ||
1020 | JS_LOCK_RUNTIME(rt); | ||
1021 | } | ||
1022 | |||
1023 | JS_PUBLIC_API(void) | ||
1024 | JS_Unlock(JSRuntime *rt) | ||
1025 | { | ||
1026 | JS_UNLOCK_RUNTIME(rt); | ||
1027 | } | ||
1028 | |||
1029 | JS_PUBLIC_API(JSContextCallback) | ||
1030 | JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback) | ||
1031 | { | ||
1032 | JSContextCallback old; | ||
1033 | |||
1034 | old = rt->cxCallback; | ||
1035 | rt->cxCallback = cxCallback; | ||
1036 | return old; | ||
1037 | } | ||
1038 | |||
1039 | JS_PUBLIC_API(JSContext *) | ||
1040 | JS_NewContext(JSRuntime *rt, size_t stackChunkSize) | ||
1041 | { | ||
1042 | return js_NewContext(rt, stackChunkSize); | ||
1043 | } | ||
1044 | |||
1045 | JS_PUBLIC_API(void) | ||
1046 | JS_DestroyContext(JSContext *cx) | ||
1047 | { | ||
1048 | js_DestroyContext(cx, JSDCM_FORCE_GC); | ||
1049 | } | ||
1050 | |||
1051 | JS_PUBLIC_API(void) | ||
1052 | JS_DestroyContextNoGC(JSContext *cx) | ||
1053 | { | ||
1054 | js_DestroyContext(cx, JSDCM_NO_GC); | ||
1055 | } | ||
1056 | |||
1057 | JS_PUBLIC_API(void) | ||
1058 | JS_DestroyContextMaybeGC(JSContext *cx) | ||
1059 | { | ||
1060 | js_DestroyContext(cx, JSDCM_MAYBE_GC); | ||
1061 | } | ||
1062 | |||
1063 | JS_PUBLIC_API(void *) | ||
1064 | JS_GetContextPrivate(JSContext *cx) | ||
1065 | { | ||
1066 | return cx->data; | ||
1067 | } | ||
1068 | |||
1069 | JS_PUBLIC_API(void) | ||
1070 | JS_SetContextPrivate(JSContext *cx, void *data) | ||
1071 | { | ||
1072 | cx->data = data; | ||
1073 | } | ||
1074 | |||
1075 | JS_PUBLIC_API(JSRuntime *) | ||
1076 | JS_GetRuntime(JSContext *cx) | ||
1077 | { | ||
1078 | return cx->runtime; | ||
1079 | } | ||
1080 | |||
1081 | JS_PUBLIC_API(JSContext *) | ||
1082 | JS_ContextIterator(JSRuntime *rt, JSContext **iterp) | ||
1083 | { | ||
1084 | return js_ContextIterator(rt, JS_TRUE, iterp); | ||
1085 | } | ||
1086 | |||
1087 | JS_PUBLIC_API(JSVersion) | ||
1088 | JS_GetVersion(JSContext *cx) | ||
1089 | { | ||
1090 | return JSVERSION_NUMBER(cx); | ||
1091 | } | ||
1092 | |||
1093 | JS_PUBLIC_API(JSVersion) | ||
1094 | JS_SetVersion(JSContext *cx, JSVersion version) | ||
1095 | { | ||
1096 | JSVersion oldVersion; | ||
1097 | |||
1098 | JS_ASSERT(version != JSVERSION_UNKNOWN); | ||
1099 | JS_ASSERT((version & ~JSVERSION_MASK) == 0); | ||
1100 | |||
1101 | oldVersion = JSVERSION_NUMBER(cx); | ||
1102 | if (version == oldVersion) | ||
1103 | return oldVersion; | ||
1104 | |||
1105 | /* We no longer support 1.4 or below. */ | ||
1106 | if (version != JSVERSION_DEFAULT && version <= JSVERSION_1_4) | ||
1107 | return oldVersion; | ||
1108 | |||
1109 | cx->version = (cx->version & ~JSVERSION_MASK) | version; | ||
1110 | js_OnVersionChange(cx); | ||
1111 | return oldVersion; | ||
1112 | } | ||
1113 | |||
1114 | static struct v2smap { | ||
1115 | JSVersion version; | ||
1116 | const char *string; | ||
1117 | } v2smap[] = { | ||
1118 | {JSVERSION_1_0, "1.0"}, | ||
1119 | {JSVERSION_1_1, "1.1"}, | ||
1120 | {JSVERSION_1_2, "1.2"}, | ||
1121 | {JSVERSION_1_3, "1.3"}, | ||
1122 | {JSVERSION_1_4, "1.4"}, | ||
1123 | {JSVERSION_ECMA_3, "ECMAv3"}, | ||
1124 | {JSVERSION_1_5, "1.5"}, | ||
1125 | {JSVERSION_1_6, "1.6"}, | ||
1126 | {JSVERSION_1_7, "1.7"}, | ||
1127 | {JSVERSION_1_8, "1.8"}, | ||
1128 | {JSVERSION_DEFAULT, js_default_str}, | ||
1129 | {JSVERSION_UNKNOWN, NULL}, /* must be last, NULL is sentinel */ | ||
1130 | }; | ||
1131 | |||
1132 | JS_PUBLIC_API(const char *) | ||
1133 | JS_VersionToString(JSVersion version) | ||
1134 | { | ||
1135 | int i; | ||
1136 | |||
1137 | for (i = 0; v2smap[i].string; i++) | ||
1138 | if (v2smap[i].version == version) | ||
1139 | return v2smap[i].string; | ||
1140 | return "unknown"; | ||
1141 | } | ||
1142 | |||
1143 | JS_PUBLIC_API(JSVersion) | ||
1144 | JS_StringToVersion(const char *string) | ||
1145 | { | ||
1146 | int i; | ||
1147 | |||
1148 | for (i = 0; v2smap[i].string; i++) | ||
1149 | if (strcmp(v2smap[i].string, string) == 0) | ||
1150 | return v2smap[i].version; | ||
1151 | return JSVERSION_UNKNOWN; | ||
1152 | } | ||
1153 | |||
1154 | JS_PUBLIC_API(uint32) | ||
1155 | JS_GetOptions(JSContext *cx) | ||
1156 | { | ||
1157 | return cx->options; | ||
1158 | } | ||
1159 | |||
1160 | JS_PUBLIC_API(uint32) | ||
1161 | JS_SetOptions(JSContext *cx, uint32 options) | ||
1162 | { | ||
1163 | uint32 oldopts = cx->options; | ||
1164 | cx->options = options; | ||
1165 | siliconforks | 460 | js_SyncOptionsToVersion(cx); |
1166 | siliconforks | 332 | return oldopts; |
1167 | } | ||
1168 | |||
1169 | JS_PUBLIC_API(uint32) | ||
1170 | JS_ToggleOptions(JSContext *cx, uint32 options) | ||
1171 | { | ||
1172 | uint32 oldopts = cx->options; | ||
1173 | cx->options ^= options; | ||
1174 | siliconforks | 460 | js_SyncOptionsToVersion(cx); |
1175 | siliconforks | 332 | return oldopts; |
1176 | } | ||
1177 | |||
1178 | JS_PUBLIC_API(const char *) | ||
1179 | JS_GetImplementationVersion(void) | ||
1180 | { | ||
1181 | return "JavaScript-C 1.8.0 pre-release 1 2007-10-03"; | ||
1182 | } | ||
1183 | |||
1184 | |||
1185 | JS_PUBLIC_API(JSObject *) | ||
1186 | JS_GetGlobalObject(JSContext *cx) | ||
1187 | { | ||
1188 | return cx->globalObject; | ||
1189 | } | ||
1190 | |||
1191 | JS_PUBLIC_API(void) | ||
1192 | JS_SetGlobalObject(JSContext *cx, JSObject *obj) | ||
1193 | { | ||
1194 | cx->globalObject = obj; | ||
1195 | |||
1196 | #if JS_HAS_XML_SUPPORT | ||
1197 | cx->xmlSettingFlags = 0; | ||
1198 | #endif | ||
1199 | } | ||
1200 | |||
1201 | JS_BEGIN_EXTERN_C | ||
1202 | |||
1203 | JSObject * | ||
1204 | js_InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj) | ||
1205 | { | ||
1206 | JSDHashTable *table; | ||
1207 | JSBool resolving; | ||
1208 | JSRuntime *rt; | ||
1209 | JSResolvingKey key; | ||
1210 | JSResolvingEntry *entry; | ||
1211 | JSObject *fun_proto, *obj_proto; | ||
1212 | |||
1213 | /* If cx has no global object, use obj so prototypes can be found. */ | ||
1214 | if (!cx->globalObject) | ||
1215 | JS_SetGlobalObject(cx, obj); | ||
1216 | |||
1217 | /* Record Function and Object in cx->resolvingTable, if we are resolving. */ | ||
1218 | table = cx->resolvingTable; | ||
1219 | resolving = (table && table->entryCount); | ||
1220 | rt = cx->runtime; | ||
1221 | key.obj = obj; | ||
1222 | if (resolving) { | ||
1223 | key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]); | ||
1224 | entry = (JSResolvingEntry *) | ||
1225 | JS_DHashTableOperate(table, &key, JS_DHASH_ADD); | ||
1226 | if (entry && entry->key.obj && (entry->flags & JSRESFLAG_LOOKUP)) { | ||
1227 | /* Already resolving Function, record Object too. */ | ||
1228 | JS_ASSERT(entry->key.obj == obj); | ||
1229 | key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]); | ||
1230 | entry = (JSResolvingEntry *) | ||
1231 | JS_DHashTableOperate(table, &key, JS_DHASH_ADD); | ||
1232 | } | ||
1233 | if (!entry) { | ||
1234 | JS_ReportOutOfMemory(cx); | ||
1235 | return NULL; | ||
1236 | } | ||
1237 | JS_ASSERT(!entry->key.obj && entry->flags == 0); | ||
1238 | entry->key = key; | ||
1239 | entry->flags = JSRESFLAG_LOOKUP; | ||
1240 | } else { | ||
1241 | key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]); | ||
1242 | if (!js_StartResolving(cx, &key, JSRESFLAG_LOOKUP, &entry)) | ||
1243 | return NULL; | ||
1244 | |||
1245 | key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]); | ||
1246 | if (!js_StartResolving(cx, &key, JSRESFLAG_LOOKUP, &entry)) { | ||
1247 | key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]); | ||
1248 | JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE); | ||
1249 | return NULL; | ||
1250 | } | ||
1251 | |||
1252 | table = cx->resolvingTable; | ||
1253 | } | ||
1254 | |||
1255 | /* Initialize the function class first so constructors can be made. */ | ||
1256 | if (!js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Function), | ||
1257 | &fun_proto)) { | ||
1258 | fun_proto = NULL; | ||
1259 | goto out; | ||
1260 | } | ||
1261 | if (!fun_proto) { | ||
1262 | fun_proto = js_InitFunctionClass(cx, obj); | ||
1263 | if (!fun_proto) | ||
1264 | goto out; | ||
1265 | } else { | ||
1266 | JSObject *ctor; | ||
1267 | |||
1268 | ctor = JS_GetConstructor(cx, fun_proto); | ||
1269 | if (!ctor) { | ||
1270 | fun_proto = NULL; | ||
1271 | goto out; | ||
1272 | } | ||
1273 | OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(CLASS_ATOM(cx, Function)), | ||
1274 | OBJECT_TO_JSVAL(ctor), 0, 0, 0, NULL); | ||
1275 | } | ||
1276 | |||
1277 | /* Initialize the object class next so Object.prototype works. */ | ||
1278 | if (!js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Object), | ||
1279 | &obj_proto)) { | ||
1280 | fun_proto = NULL; | ||
1281 | goto out; | ||
1282 | } | ||
1283 | if (!obj_proto) | ||
1284 | obj_proto = js_InitObjectClass(cx, obj); | ||
1285 | if (!obj_proto) { | ||
1286 | fun_proto = NULL; | ||
1287 | goto out; | ||
1288 | } | ||
1289 | |||
1290 | /* Function.prototype and the global object delegate to Object.prototype. */ | ||
1291 | OBJ_SET_PROTO(cx, fun_proto, obj_proto); | ||
1292 | if (!OBJ_GET_PROTO(cx, obj)) | ||
1293 | OBJ_SET_PROTO(cx, obj, obj_proto); | ||
1294 | |||
1295 | out: | ||
1296 | /* If resolving, remove the other entry (Object or Function) from table. */ | ||
1297 | JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE); | ||
1298 | if (!resolving) { | ||
1299 | /* If not resolving, remove the first entry added above, for Object. */ | ||
1300 | JS_ASSERT(key.id == \ | ||
1301 | ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function])); | ||
1302 | key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]); | ||
1303 | JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE); | ||
1304 | } | ||
1305 | return fun_proto; | ||
1306 | } | ||
1307 | |||
1308 | JS_END_EXTERN_C | ||
1309 | |||
1310 | JS_PUBLIC_API(JSBool) | ||
1311 | JS_InitStandardClasses(JSContext *cx, JSObject *obj) | ||
1312 | { | ||
1313 | JSAtom *atom; | ||
1314 | |||
1315 | CHECK_REQUEST(cx); | ||
1316 | |||
1317 | /* Define a top-level property 'undefined' with the undefined value. */ | ||
1318 | atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID]; | ||
1319 | if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID, | ||
1320 | siliconforks | 460 | JS_PropertyStub, JS_PropertyStub, JSPROP_PERMANENT, |
1321 | NULL)) { | ||
1322 | siliconforks | 332 | return JS_FALSE; |
1323 | } | ||
1324 | |||
1325 | /* Function and Object require cooperative bootstrapping magic. */ | ||
1326 | if (!js_InitFunctionAndObjectClasses(cx, obj)) | ||
1327 | return JS_FALSE; | ||
1328 | |||
1329 | /* Initialize the rest of the standard objects and functions. */ | ||
1330 | return js_InitArrayClass(cx, obj) && | ||
1331 | js_InitBooleanClass(cx, obj) && | ||
1332 | js_InitExceptionClasses(cx, obj) && | ||
1333 | js_InitMathClass(cx, obj) && | ||
1334 | js_InitNumberClass(cx, obj) && | ||
1335 | js_InitJSONClass(cx, obj) && | ||
1336 | js_InitRegExpClass(cx, obj) && | ||
1337 | js_InitStringClass(cx, obj) && | ||
1338 | js_InitEval(cx, obj) && | ||
1339 | #if JS_HAS_SCRIPT_OBJECT | ||
1340 | js_InitScriptClass(cx, obj) && | ||
1341 | #endif | ||
1342 | #if JS_HAS_XML_SUPPORT | ||
1343 | js_InitXMLClasses(cx, obj) && | ||
1344 | #endif | ||
1345 | #if JS_HAS_FILE_OBJECT | ||
1346 | js_InitFileClass(cx, obj) && | ||
1347 | #endif | ||
1348 | #if JS_HAS_GENERATORS | ||
1349 | js_InitIteratorClasses(cx, obj) && | ||
1350 | #endif | ||
1351 | js_InitDateClass(cx, obj); | ||
1352 | } | ||
1353 | |||
1354 | #define CLASP(name) (&js_##name##Class) | ||
1355 | siliconforks | 460 | #define XCLASP(name) (&js_##name##Class.base) |
1356 | siliconforks | 332 | #define EAGER_ATOM(name) ATOM_OFFSET(name), NULL |
1357 | #define EAGER_CLASS_ATOM(name) CLASS_ATOM_OFFSET(name), NULL | ||
1358 | #define EAGER_ATOM_AND_CLASP(name) EAGER_CLASS_ATOM(name), CLASP(name) | ||
1359 | siliconforks | 460 | #define EAGER_ATOM_AND_XCLASP(name) EAGER_CLASS_ATOM(name), XCLASP(name) |
1360 | siliconforks | 332 | #define LAZY_ATOM(name) ATOM_OFFSET(lazy.name), js_##name##_str |
1361 | |||
1362 | typedef struct JSStdName { | ||
1363 | JSObjectOp init; | ||
1364 | size_t atomOffset; /* offset of atom pointer in JSAtomState */ | ||
1365 | const char *name; /* null if atom is pre-pinned, else name */ | ||
1366 | JSClass *clasp; | ||
1367 | } JSStdName; | ||
1368 | |||
1369 | static JSAtom * | ||
1370 | StdNameToAtom(JSContext *cx, JSStdName *stdn) | ||
1371 | { | ||
1372 | size_t offset; | ||
1373 | JSAtom *atom; | ||
1374 | const char *name; | ||
1375 | |||
1376 | offset = stdn->atomOffset; | ||
1377 | atom = OFFSET_TO_ATOM(cx->runtime, offset); | ||
1378 | if (!atom) { | ||
1379 | name = stdn->name; | ||
1380 | if (name) { | ||
1381 | atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED); | ||
1382 | OFFSET_TO_ATOM(cx->runtime, offset) = atom; | ||
1383 | } | ||
1384 | } | ||
1385 | return atom; | ||
1386 | } | ||
1387 | |||
1388 | /* | ||
1389 | * Table of class initializers and their atom offsets in rt->atomState. | ||
1390 | * If you add a "standard" class, remember to update this table. | ||
1391 | */ | ||
1392 | static JSStdName standard_class_atoms[] = { | ||
1393 | {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Function)}, | ||
1394 | {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Object)}, | ||
1395 | {js_InitArrayClass, EAGER_ATOM_AND_CLASP(Array)}, | ||
1396 | {js_InitBooleanClass, EAGER_ATOM_AND_CLASP(Boolean)}, | ||
1397 | {js_InitDateClass, EAGER_ATOM_AND_CLASP(Date)}, | ||
1398 | {js_InitMathClass, EAGER_ATOM_AND_CLASP(Math)}, | ||
1399 | {js_InitNumberClass, EAGER_ATOM_AND_CLASP(Number)}, | ||
1400 | {js_InitStringClass, EAGER_ATOM_AND_CLASP(String)}, | ||
1401 | {js_InitExceptionClasses, EAGER_ATOM_AND_CLASP(Error)}, | ||
1402 | {js_InitRegExpClass, EAGER_ATOM_AND_CLASP(RegExp)}, | ||
1403 | #if JS_HAS_SCRIPT_OBJECT | ||
1404 | {js_InitScriptClass, EAGER_ATOM_AND_CLASP(Script)}, | ||
1405 | #endif | ||
1406 | #if JS_HAS_XML_SUPPORT | ||
1407 | {js_InitXMLClass, EAGER_ATOM_AND_CLASP(XML)}, | ||
1408 | siliconforks | 460 | {js_InitNamespaceClass, EAGER_ATOM_AND_XCLASP(Namespace)}, |
1409 | {js_InitQNameClass, EAGER_ATOM_AND_XCLASP(QName)}, | ||
1410 | siliconforks | 332 | #endif |
1411 | #if JS_HAS_FILE_OBJECT | ||
1412 | {js_InitFileClass, EAGER_ATOM_AND_CLASP(File)}, | ||
1413 | #endif | ||
1414 | #if JS_HAS_GENERATORS | ||
1415 | {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(StopIteration)}, | ||
1416 | #endif | ||
1417 | {js_InitJSONClass, EAGER_ATOM_AND_CLASP(JSON)}, | ||
1418 | {NULL, 0, NULL, NULL} | ||
1419 | }; | ||
1420 | |||
1421 | /* | ||
1422 | * Table of top-level function and constant names and their init functions. | ||
1423 | * If you add a "standard" global function or property, remember to update | ||
1424 | * this table. | ||
1425 | */ | ||
1426 | static JSStdName standard_class_names[] = { | ||
1427 | /* ECMA requires that eval be a direct property of the global object. */ | ||
1428 | {js_InitEval, EAGER_ATOM(eval), NULL}, | ||
1429 | |||
1430 | /* Global properties and functions defined by the Number class. */ | ||
1431 | {js_InitNumberClass, LAZY_ATOM(NaN), NULL}, | ||
1432 | {js_InitNumberClass, LAZY_ATOM(Infinity), NULL}, | ||
1433 | {js_InitNumberClass, LAZY_ATOM(isNaN), NULL}, | ||
1434 | {js_InitNumberClass, LAZY_ATOM(isFinite), NULL}, | ||
1435 | {js_InitNumberClass, LAZY_ATOM(parseFloat), NULL}, | ||
1436 | {js_InitNumberClass, LAZY_ATOM(parseInt), NULL}, | ||
1437 | |||
1438 | /* String global functions. */ | ||
1439 | {js_InitStringClass, LAZY_ATOM(escape), NULL}, | ||
1440 | {js_InitStringClass, LAZY_ATOM(unescape), NULL}, | ||
1441 | {js_InitStringClass, LAZY_ATOM(decodeURI), NULL}, | ||
1442 | {js_InitStringClass, LAZY_ATOM(encodeURI), NULL}, | ||
1443 | {js_InitStringClass, LAZY_ATOM(decodeURIComponent), NULL}, | ||
1444 | {js_InitStringClass, LAZY_ATOM(encodeURIComponent), NULL}, | ||
1445 | #if JS_HAS_UNEVAL | ||
1446 | {js_InitStringClass, LAZY_ATOM(uneval), NULL}, | ||
1447 | #endif | ||
1448 | |||
1449 | /* Exception constructors. */ | ||
1450 | {js_InitExceptionClasses, EAGER_CLASS_ATOM(Error), CLASP(Error)}, | ||
1451 | {js_InitExceptionClasses, EAGER_CLASS_ATOM(InternalError), CLASP(Error)}, | ||
1452 | {js_InitExceptionClasses, EAGER_CLASS_ATOM(EvalError), CLASP(Error)}, | ||
1453 | {js_InitExceptionClasses, EAGER_CLASS_ATOM(RangeError), CLASP(Error)}, | ||
1454 | {js_InitExceptionClasses, EAGER_CLASS_ATOM(ReferenceError), CLASP(Error)}, | ||
1455 | {js_InitExceptionClasses, EAGER_CLASS_ATOM(SyntaxError), CLASP(Error)}, | ||
1456 | {js_InitExceptionClasses, EAGER_CLASS_ATOM(TypeError), CLASP(Error)}, | ||
1457 | {js_InitExceptionClasses, EAGER_CLASS_ATOM(URIError), CLASP(Error)}, | ||
1458 | |||
1459 | #if JS_HAS_XML_SUPPORT | ||
1460 | {js_InitAnyNameClass, EAGER_ATOM_AND_CLASP(AnyName)}, | ||
1461 | {js_InitAttributeNameClass, EAGER_ATOM_AND_CLASP(AttributeName)}, | ||
1462 | {js_InitXMLClass, LAZY_ATOM(XMLList), &js_XMLClass}, | ||
1463 | {js_InitXMLClass, LAZY_ATOM(isXMLName), NULL}, | ||
1464 | #endif | ||
1465 | |||
1466 | #if JS_HAS_GENERATORS | ||
1467 | {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Iterator)}, | ||
1468 | {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Generator)}, | ||
1469 | #endif | ||
1470 | |||
1471 | {NULL, 0, NULL, NULL} | ||
1472 | }; | ||
1473 | |||
1474 | static JSStdName object_prototype_names[] = { | ||
1475 | /* Object.prototype properties (global delegates to Object.prototype). */ | ||
1476 | {js_InitObjectClass, EAGER_ATOM(proto), NULL}, | ||
1477 | {js_InitObjectClass, EAGER_ATOM(parent), NULL}, | ||
1478 | {js_InitObjectClass, EAGER_ATOM(count), NULL}, | ||
1479 | #if JS_HAS_TOSOURCE | ||
1480 | {js_InitObjectClass, EAGER_ATOM(toSource), NULL}, | ||
1481 | #endif | ||
1482 | {js_InitObjectClass, EAGER_ATOM(toString), NULL}, | ||
1483 | {js_InitObjectClass, EAGER_ATOM(toLocaleString), NULL}, | ||
1484 | {js_InitObjectClass, EAGER_ATOM(valueOf), NULL}, | ||
1485 | #if JS_HAS_OBJ_WATCHPOINT | ||
1486 | {js_InitObjectClass, LAZY_ATOM(watch), NULL}, | ||
1487 | {js_InitObjectClass, LAZY_ATOM(unwatch), NULL}, | ||
1488 | #endif | ||
1489 | {js_InitObjectClass, LAZY_ATOM(hasOwnProperty), NULL}, | ||
1490 | {js_InitObjectClass, LAZY_ATOM(isPrototypeOf), NULL}, | ||
1491 | {js_InitObjectClass, LAZY_ATOM(propertyIsEnumerable), NULL}, | ||
1492 | #if JS_HAS_GETTER_SETTER | ||
1493 | {js_InitObjectClass, LAZY_ATOM(defineGetter), NULL}, | ||
1494 | {js_InitObjectClass, LAZY_ATOM(defineSetter), NULL}, | ||
1495 | {js_InitObjectClass, LAZY_ATOM(lookupGetter), NULL}, | ||
1496 | {js_InitObjectClass, LAZY_ATOM(lookupSetter), NULL}, | ||
1497 | #endif | ||
1498 | |||
1499 | {NULL, 0, NULL, NULL} | ||
1500 | }; | ||
1501 | |||
1502 | JS_PUBLIC_API(JSBool) | ||
1503 | JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id, | ||
1504 | JSBool *resolved) | ||
1505 | { | ||
1506 | JSString *idstr; | ||
1507 | JSRuntime *rt; | ||
1508 | JSAtom *atom; | ||
1509 | JSStdName *stdnm; | ||
1510 | uintN i; | ||
1511 | |||
1512 | CHECK_REQUEST(cx); | ||
1513 | *resolved = JS_FALSE; | ||
1514 | |||
1515 | rt = cx->runtime; | ||
1516 | JS_ASSERT(rt->state != JSRTS_DOWN); | ||
1517 | if (rt->state == JSRTS_LANDING || !JSVAL_IS_STRING(id)) | ||
1518 | return JS_TRUE; | ||
1519 | |||
1520 | idstr = JSVAL_TO_STRING(id); | ||
1521 | |||
1522 | /* Check whether we're resolving 'undefined', and define it if so. */ | ||
1523 | atom = rt->atomState.typeAtoms[JSTYPE_VOID]; | ||
1524 | if (idstr == ATOM_TO_STRING(atom)) { | ||
1525 | *resolved = JS_TRUE; | ||
1526 | return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID, | ||
1527 | siliconforks | 460 | JS_PropertyStub, JS_PropertyStub, |
1528 | JSPROP_PERMANENT, NULL); | ||
1529 | siliconforks | 332 | } |
1530 | |||
1531 | /* Try for class constructors/prototypes named by well-known atoms. */ | ||
1532 | stdnm = NULL; | ||
1533 | for (i = 0; standard_class_atoms[i].init; i++) { | ||
1534 | atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset); | ||
1535 | if (idstr == ATOM_TO_STRING(atom)) { | ||
1536 | stdnm = &standard_class_atoms[i]; | ||
1537 | break; | ||
1538 | } | ||
1539 | } | ||
1540 | |||
1541 | if (!stdnm) { | ||
1542 | /* Try less frequently used top-level functions and constants. */ | ||
1543 | for (i = 0; standard_class_names[i].init; i++) { | ||
1544 | atom = StdNameToAtom(cx, &standard_class_names[i]); | ||
1545 | if (!atom) | ||
1546 | return JS_FALSE; | ||
1547 | if (idstr == ATOM_TO_STRING(atom)) { | ||
1548 | stdnm = &standard_class_names[i]; | ||
1549 | break; | ||
1550 | } | ||
1551 | } | ||
1552 | |||
1553 | if (!stdnm && !OBJ_GET_PROTO(cx, obj)) { | ||
1554 | /* | ||
1555 | * Try even less frequently used names delegated from the global | ||
1556 | * object to Object.prototype, but only if the Object class hasn't | ||
1557 | * yet been initialized. | ||
1558 | */ | ||
1559 | for (i = 0; object_prototype_names[i].init; i++) { | ||
1560 | atom = StdNameToAtom(cx, &object_prototype_names[i]); | ||
1561 | if (!atom) | ||
1562 | return JS_FALSE; | ||
1563 | if (idstr == ATOM_TO_STRING(atom)) { | ||
1564 | stdnm = &standard_class_names[i]; | ||
1565 | break; | ||
1566 | } | ||
1567 | } | ||
1568 | } | ||
1569 | } | ||
1570 | |||
1571 | if (stdnm) { | ||
1572 | /* | ||
1573 | * If this standard class is anonymous and obj advertises itself as a | ||
1574 | * global object (in order to reserve slots for standard class object | ||
1575 | * pointers), then we don't want to resolve by name. | ||
1576 | * | ||
1577 | * If inversely, either id does not name a class, or id does not name | ||
1578 | * an anonymous class, or the global does not reserve slots for class | ||
1579 | * objects, then we must call the init hook here. | ||
1580 | */ | ||
1581 | if (stdnm->clasp && | ||
1582 | (stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS) && | ||
1583 | (OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_IS_GLOBAL)) { | ||
1584 | return JS_TRUE; | ||
1585 | } | ||
1586 | |||
1587 | if (!stdnm->init(cx, obj)) | ||
1588 | return JS_FALSE; | ||
1589 | *resolved = JS_TRUE; | ||
1590 | } | ||
1591 | return JS_TRUE; | ||
1592 | } | ||
1593 | |||
1594 | static JSBool | ||
1595 | AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, JSAtom *atom) | ||
1596 | { | ||
1597 | JSScopeProperty *sprop; | ||
1598 | JSScope *scope; | ||
1599 | |||
1600 | JS_ASSERT(OBJ_IS_NATIVE(obj)); | ||
1601 | JS_LOCK_OBJ(cx, obj); | ||
1602 | scope = OBJ_SCOPE(obj); | ||
1603 | sprop = SCOPE_GET_PROPERTY(scope, ATOM_TO_JSID(atom)); | ||
1604 | JS_UNLOCK_SCOPE(cx, scope); | ||
1605 | return sprop != NULL; | ||
1606 | } | ||
1607 | |||
1608 | JS_PUBLIC_API(JSBool) | ||
1609 | JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj) | ||
1610 | { | ||
1611 | JSRuntime *rt; | ||
1612 | JSAtom *atom; | ||
1613 | uintN i; | ||
1614 | |||
1615 | CHECK_REQUEST(cx); | ||
1616 | rt = cx->runtime; | ||
1617 | |||
1618 | /* Check whether we need to bind 'undefined' and define it if so. */ | ||
1619 | atom = rt->atomState.typeAtoms[JSTYPE_VOID]; | ||
1620 | if (!AlreadyHasOwnProperty(cx, obj, atom) && | ||
1621 | !OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID, | ||
1622 | siliconforks | 460 | JS_PropertyStub, JS_PropertyStub, JSPROP_PERMANENT, |
1623 | NULL)) { | ||
1624 | siliconforks | 332 | return JS_FALSE; |
1625 | } | ||
1626 | |||
1627 | /* Initialize any classes that have not been resolved yet. */ | ||
1628 | for (i = 0; standard_class_atoms[i].init; i++) { | ||
1629 | atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset); | ||
1630 | if (!AlreadyHasOwnProperty(cx, obj, atom) && | ||
1631 | !standard_class_atoms[i].init(cx, obj)) { | ||
1632 | return JS_FALSE; | ||
1633 | } | ||
1634 | } | ||
1635 | |||
1636 | return JS_TRUE; | ||
1637 | } | ||
1638 | |||
1639 | static JSIdArray * | ||
1640 | NewIdArray(JSContext *cx, jsint length) | ||
1641 | { | ||
1642 | JSIdArray *ida; | ||
1643 | |||
1644 | ida = (JSIdArray *) | ||
1645 | JS_malloc(cx, offsetof(JSIdArray, vector) + length * sizeof(jsval)); | ||
1646 | if (ida) | ||
1647 | ida->length = length; | ||
1648 | return ida; | ||
1649 | } | ||
1650 | |||
1651 | /* | ||
1652 | * Unlike realloc(3), this function frees ida on failure. | ||
1653 | */ | ||
1654 | static JSIdArray * | ||
1655 | SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length) | ||
1656 | { | ||
1657 | JSIdArray *rida; | ||
1658 | |||
1659 | rida = (JSIdArray *) | ||
1660 | JS_realloc(cx, ida, | ||
1661 | offsetof(JSIdArray, vector) + length * sizeof(jsval)); | ||
1662 | if (!rida) | ||
1663 | JS_DestroyIdArray(cx, ida); | ||
1664 | else | ||
1665 | rida->length = length; | ||
1666 | return rida; | ||
1667 | } | ||
1668 | |||
1669 | static JSIdArray * | ||
1670 | AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip) | ||
1671 | { | ||
1672 | jsint i, length; | ||
1673 | |||
1674 | i = *ip; | ||
1675 | length = ida->length; | ||
1676 | if (i >= length) { | ||
1677 | ida = SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8)); | ||
1678 | if (!ida) | ||
1679 | return NULL; | ||
1680 | JS_ASSERT(i < ida->length); | ||
1681 | } | ||
1682 | ida->vector[i] = ATOM_TO_JSID(atom); | ||
1683 | *ip = i + 1; | ||
1684 | return ida; | ||
1685 | } | ||
1686 | |||
1687 | static JSIdArray * | ||
1688 | EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida, | ||
1689 | jsint *ip, JSBool *foundp) | ||
1690 | { | ||
1691 | *foundp = AlreadyHasOwnProperty(cx, obj, atom); | ||
1692 | if (*foundp) | ||
1693 | ida = AddAtomToArray(cx, atom, ida, ip); | ||
1694 | return ida; | ||
1695 | } | ||
1696 | |||
1697 | JS_PUBLIC_API(JSIdArray *) | ||
1698 | JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj, | ||
1699 | JSIdArray *ida) | ||
1700 | { | ||
1701 | JSRuntime *rt; | ||
1702 | jsint i, j, k; | ||
1703 | JSAtom *atom; | ||
1704 | JSBool found; | ||
1705 | JSObjectOp init; | ||
1706 | |||
1707 | CHECK_REQUEST(cx); | ||
1708 | rt = cx->runtime; | ||
1709 | if (ida) { | ||
1710 | i = ida->length; | ||
1711 | } else { | ||
1712 | ida = NewIdArray(cx, 8); | ||
1713 | if (!ida) | ||
1714 | return NULL; | ||
1715 | i = 0; | ||
1716 | } | ||
1717 | |||
1718 | /* Check whether 'undefined' has been resolved and enumerate it if so. */ | ||
1719 | atom = rt->atomState.typeAtoms[JSTYPE_VOID]; | ||
1720 | ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found); | ||
1721 | if (!ida) | ||
1722 | return NULL; | ||
1723 | |||
1724 | /* Enumerate only classes that *have* been resolved. */ | ||
1725 | for (j = 0; standard_class_atoms[j].init; j++) { | ||
1726 | atom = OFFSET_TO_ATOM(rt, standard_class_atoms[j].atomOffset); | ||
1727 | ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found); | ||
1728 | if (!ida) | ||
1729 | return NULL; | ||
1730 | |||
1731 | if (found) { | ||
1732 | init = standard_class_atoms[j].init; | ||
1733 | |||
1734 | for (k = 0; standard_class_names[k].init; k++) { | ||
1735 | if (standard_class_names[k].init == init) { | ||
1736 | atom = StdNameToAtom(cx, &standard_class_names[k]); | ||
1737 | ida = AddAtomToArray(cx, atom, ida, &i); | ||
1738 | if (!ida) | ||
1739 | return NULL; | ||
1740 | } | ||
1741 | } | ||
1742 | |||
1743 | if (init == js_InitObjectClass) { | ||
1744 | for (k = 0; object_prototype_names[k].init; k++) { | ||
1745 | atom = StdNameToAtom(cx, &object_prototype_names[k]); | ||
1746 | ida = AddAtomToArray(cx, atom, ida, &i); | ||
1747 | if (!ida) | ||
1748 | return NULL; | ||
1749 | } | ||
1750 | } | ||
1751 | } | ||
1752 | } | ||
1753 | |||
1754 | /* Trim to exact length. */ | ||
1755 | return SetIdArrayLength(cx, ida, i); | ||
1756 | } | ||
1757 | |||
1758 | #undef CLASP | ||
1759 | #undef EAGER_ATOM | ||
1760 | #undef EAGER_CLASS_ATOM | ||
1761 | #undef EAGER_ATOM_CLASP | ||
1762 | #undef LAZY_ATOM | ||
1763 | |||
1764 | JS_PUBLIC_API(JSBool) | ||
1765 | JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, | ||
1766 | JSObject **objp) | ||
1767 | { | ||
1768 | CHECK_REQUEST(cx); | ||
1769 | return js_GetClassObject(cx, obj, key, objp); | ||
1770 | } | ||
1771 | |||
1772 | JS_PUBLIC_API(JSObject *) | ||
1773 | JS_GetScopeChain(JSContext *cx) | ||
1774 | { | ||
1775 | JSStackFrame *fp; | ||
1776 | |||
1777 | CHECK_REQUEST(cx); | ||
1778 | siliconforks | 460 | fp = js_GetTopStackFrame(cx); |
1779 | siliconforks | 332 | if (!fp) { |
1780 | /* | ||
1781 | * There is no code active on this context. In place of an actual | ||
1782 | * scope chain, use the context's global object, which is set in | ||
1783 | * js_InitFunctionAndObjectClasses, and which represents the default | ||
1784 | * scope chain for the embedding. See also js_FindClassObject. | ||
1785 | * | ||
1786 | * For embeddings that use the inner and outer object hooks, the inner | ||
1787 | * object represents the ultimate global object, with the outer object | ||
1788 | * acting as a stand-in. | ||
1789 | */ | ||
1790 | JSObject *obj = cx->globalObject; | ||
1791 | if (!obj) { | ||
1792 | JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE); | ||
1793 | return NULL; | ||
1794 | } | ||
1795 | |||
1796 | OBJ_TO_INNER_OBJECT(cx, obj); | ||
1797 | return obj; | ||
1798 | } | ||
1799 | return js_GetScopeChain(cx, fp); | ||
1800 | } | ||
1801 | |||
1802 | JS_PUBLIC_API(JSObject *) | ||
1803 | JS_GetGlobalForObject(JSContext *cx, JSObject *obj) | ||
1804 | { | ||
1805 | JSObject *parent; | ||
1806 | |||
1807 | while ((parent = OBJ_GET_PARENT(cx, obj)) != NULL) | ||
1808 | obj = parent; | ||
1809 | return obj; | ||
1810 | } | ||
1811 | |||
1812 | JS_PUBLIC_API(jsval) | ||
1813 | JS_ComputeThis(JSContext *cx, jsval *vp) | ||
1814 | { | ||
1815 | if (!js_ComputeThis(cx, JS_FALSE, vp + 2)) | ||
1816 | return JSVAL_NULL; | ||
1817 | return vp[1]; | ||
1818 | } | ||
1819 | |||
1820 | JS_PUBLIC_API(void *) | ||
1821 | JS_malloc(JSContext *cx, size_t nbytes) | ||
1822 | { | ||
1823 | void *p; | ||
1824 | |||
1825 | JS_ASSERT(nbytes != 0); | ||
1826 | if (nbytes == 0) | ||
1827 | nbytes = 1; | ||
1828 | |||
1829 | p = malloc(nbytes); | ||
1830 | if (!p) { | ||
1831 | JS_ReportOutOfMemory(cx); | ||
1832 | return NULL; | ||
1833 | } | ||
1834 | js_UpdateMallocCounter(cx, nbytes); | ||
1835 | |||
1836 | return p; | ||
1837 | } | ||
1838 | |||
1839 | JS_PUBLIC_API(void *) | ||
1840 | JS_realloc(JSContext *cx, void *p, size_t nbytes) | ||
1841 | { | ||
1842 | siliconforks | 460 | void *orig = p; |
1843 | siliconforks | 332 | p = realloc(p, nbytes); |
1844 | siliconforks | 460 | if (!p) { |
1845 | siliconforks | 332 | JS_ReportOutOfMemory(cx); |
1846 | siliconforks | 460 | return NULL; |
1847 | } | ||
1848 | if (!orig) | ||
1849 | js_UpdateMallocCounter(cx, nbytes); | ||
1850 | siliconforks | 332 | return p; |
1851 | } | ||
1852 | |||
1853 | JS_PUBLIC_API(void) | ||
1854 | JS_free(JSContext *cx, void *p) | ||
1855 | { | ||
1856 | if (p) | ||
1857 | free(p); | ||
1858 | } | ||
1859 | |||
1860 | JS_PUBLIC_API(char *) | ||
1861 | JS_strdup(JSContext *cx, const char *s) | ||
1862 | { | ||
1863 | size_t n; | ||
1864 | void *p; | ||
1865 | |||
1866 | n = strlen(s) + 1; | ||
1867 | p = JS_malloc(cx, n); | ||
1868 | if (!p) | ||
1869 | return NULL; | ||
1870 | return (char *)memcpy(p, s, n); | ||
1871 | } | ||
1872 | |||
1873 | JS_PUBLIC_API(jsdouble *) | ||
1874 | JS_NewDouble(JSContext *cx, jsdouble d) | ||
1875 | { | ||
1876 | CHECK_REQUEST(cx); | ||
1877 | return js_NewWeaklyRootedDouble(cx, d); | ||
1878 | } | ||
1879 | |||
1880 | JS_PUBLIC_API(JSBool) | ||
1881 | JS_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval) | ||
1882 | { | ||
1883 | jsdouble *dp; | ||
1884 | |||
1885 | CHECK_REQUEST(cx); | ||
1886 | dp = js_NewWeaklyRootedDouble(cx, d); | ||
1887 | if (!dp) | ||
1888 | return JS_FALSE; | ||
1889 | *rval = DOUBLE_TO_JSVAL(dp); | ||
1890 | return JS_TRUE; | ||
1891 | } | ||
1892 | |||
1893 | JS_PUBLIC_API(JSBool) | ||
1894 | JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval) | ||
1895 | { | ||
1896 | CHECK_REQUEST(cx); | ||
1897 | siliconforks | 460 | return js_NewWeaklyRootedNumber(cx, d, rval); |
1898 | siliconforks | 332 | } |
1899 | |||
1900 | #undef JS_AddRoot | ||
1901 | JS_PUBLIC_API(JSBool) | ||
1902 | JS_AddRoot(JSContext *cx, void *rp) | ||
1903 | { | ||
1904 | CHECK_REQUEST(cx); | ||
1905 | return js_AddRoot(cx, rp, NULL); | ||
1906 | } | ||
1907 | |||
1908 | JS_PUBLIC_API(JSBool) | ||
1909 | JS_AddNamedRootRT(JSRuntime *rt, void *rp, const char *name) | ||
1910 | { | ||
1911 | return js_AddRootRT(rt, rp, name); | ||
1912 | } | ||
1913 | |||
1914 | JS_PUBLIC_API(JSBool) | ||
1915 | JS_RemoveRoot(JSContext *cx, void *rp) | ||
1916 | { | ||
1917 | CHECK_REQUEST(cx); | ||
1918 | return js_RemoveRoot(cx->runtime, rp); | ||
1919 | } | ||
1920 | |||
1921 | JS_PUBLIC_API(JSBool) | ||
1922 | JS_RemoveRootRT(JSRuntime *rt, void *rp) | ||
1923 | { | ||
1924 | return js_RemoveRoot(rt, rp); | ||
1925 | } | ||
1926 | |||
1927 | JS_PUBLIC_API(JSBool) | ||
1928 | JS_AddNamedRoot(JSContext *cx, void *rp, const char *name) | ||
1929 | { | ||
1930 | CHECK_REQUEST(cx); | ||
1931 | return js_AddRoot(cx, rp, name); | ||
1932 | } | ||
1933 | |||
1934 | JS_PUBLIC_API(void) | ||
1935 | JS_ClearNewbornRoots(JSContext *cx) | ||
1936 | { | ||
1937 | JS_CLEAR_WEAK_ROOTS(&cx->weakRoots); | ||
1938 | } | ||
1939 | |||
1940 | JS_PUBLIC_API(JSBool) | ||
1941 | JS_EnterLocalRootScope(JSContext *cx) | ||
1942 | { | ||
1943 | CHECK_REQUEST(cx); | ||
1944 | return js_EnterLocalRootScope(cx); | ||
1945 | } | ||
1946 | |||
1947 | JS_PUBLIC_API(void) | ||
1948 | JS_LeaveLocalRootScope(JSContext *cx) | ||
1949 | { | ||
1950 | CHECK_REQUEST(cx); | ||
1951 | js_LeaveLocalRootScope(cx); | ||
1952 | } | ||
1953 | |||
1954 | JS_PUBLIC_API(void) | ||
1955 | JS_LeaveLocalRootScopeWithResult(JSContext *cx, jsval rval) | ||
1956 | { | ||
1957 | CHECK_REQUEST(cx); | ||
1958 | js_LeaveLocalRootScopeWithResult(cx, rval); | ||
1959 | } | ||
1960 | |||
1961 | JS_PUBLIC_API(void) | ||
1962 | JS_ForgetLocalRoot(JSContext *cx, void *thing) | ||
1963 | { | ||
1964 | CHECK_REQUEST(cx); | ||
1965 | js_ForgetLocalRoot(cx, (jsval) thing); | ||
1966 | } | ||
1967 | |||
1968 | #ifdef DEBUG | ||
1969 | |||
1970 | JS_PUBLIC_API(void) | ||
1971 | JS_DumpNamedRoots(JSRuntime *rt, | ||
1972 | void (*dump)(const char *name, void *rp, void *data), | ||
1973 | void *data) | ||
1974 | { | ||
1975 | js_DumpNamedRoots(rt, dump, data); | ||
1976 | } | ||
1977 | |||
1978 | #endif /* DEBUG */ | ||
1979 | |||
1980 | JS_PUBLIC_API(uint32) | ||
1981 | JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data) | ||
1982 | { | ||
1983 | return js_MapGCRoots(rt, map, data); | ||
1984 | } | ||
1985 | |||
1986 | JS_PUBLIC_API(JSBool) | ||
1987 | JS_LockGCThing(JSContext *cx, void *thing) | ||
1988 | { | ||
1989 | JSBool ok; | ||
1990 | |||
1991 | CHECK_REQUEST(cx); | ||
1992 | ok = js_LockGCThingRT(cx->runtime, thing); | ||
1993 | if (!ok) | ||
1994 | JS_ReportOutOfMemory(cx); | ||
1995 | return ok; | ||
1996 | } | ||
1997 | |||
1998 | JS_PUBLIC_API(JSBool) | ||
1999 | JS_LockGCThingRT(JSRuntime *rt, void *thing) | ||
2000 | { | ||
2001 | return js_LockGCThingRT(rt, thing); | ||
2002 | } | ||
2003 | |||
2004 | JS_PUBLIC_API(JSBool) | ||
2005 | JS_UnlockGCThing(JSContext *cx, void *thing) | ||
2006 | { | ||
2007 | JSBool ok; | ||
2008 | |||
2009 | CHECK_REQUEST(cx); | ||
2010 | ok = js_UnlockGCThingRT(cx->runtime, thing); | ||
2011 | if (!ok) | ||
2012 | JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_UNLOCK); | ||
2013 | return ok; | ||
2014 | } | ||
2015 | |||
2016 | JS_PUBLIC_API(JSBool) | ||
2017 | JS_UnlockGCThingRT(JSRuntime *rt, void *thing) | ||
2018 | { | ||
2019 | return js_UnlockGCThingRT(rt, thing); | ||
2020 | } | ||
2021 | |||
2022 | JS_PUBLIC_API(void) | ||
2023 | JS_SetExtraGCRoots(JSRuntime *rt, JSTraceDataOp traceOp, void *data) | ||
2024 | { | ||
2025 | rt->gcExtraRootsTraceOp = traceOp; | ||
2026 | rt->gcExtraRootsData = data; | ||
2027 | } | ||
2028 | |||
2029 | JS_PUBLIC_API(void) | ||
2030 | JS_TraceRuntime(JSTracer *trc) | ||
2031 | { | ||
2032 | JSBool allAtoms = trc->context->runtime->gcKeepAtoms != 0; | ||
2033 | |||
2034 | siliconforks | 460 | js_LeaveTrace(trc->context); |
2035 | siliconforks | 332 | js_TraceRuntime(trc, allAtoms); |
2036 | } | ||
2037 | |||
2038 | #ifdef DEBUG | ||
2039 | |||
2040 | #ifdef HAVE_XPCONNECT | ||
2041 | #include "dump_xpc.h" | ||
2042 | #endif | ||
2043 | |||
2044 | JS_PUBLIC_API(void) | ||
2045 | JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, | ||
2046 | void *thing, uint32 kind, JSBool details) | ||
2047 | { | ||
2048 | const char *name; | ||
2049 | size_t n; | ||
2050 | |||
2051 | if (bufsize == 0) | ||
2052 | return; | ||
2053 | |||
2054 | switch (kind) { | ||
2055 | case JSTRACE_OBJECT: | ||
2056 | { | ||
2057 | JSObject *obj = (JSObject *)thing; | ||
2058 | JSClass *clasp = STOBJ_GET_CLASS(obj); | ||
2059 | |||
2060 | name = clasp->name; | ||
2061 | #ifdef HAVE_XPCONNECT | ||
2062 | if (clasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) { | ||
2063 | jsval privateValue = STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE); | ||
2064 | |||
2065 | JS_ASSERT(clasp->flags & JSCLASS_HAS_PRIVATE); | ||
2066 | if (!JSVAL_IS_VOID(privateValue)) { | ||
2067 | void *privateThing = JSVAL_TO_PRIVATE(privateValue); | ||
2068 | const char *xpcClassName = GetXPCObjectClassName(privateThing); | ||
2069 | |||
2070 | if (xpcClassName) | ||
2071 | name = xpcClassName; | ||
2072 | } | ||
2073 | } | ||
2074 | #endif | ||
2075 | break; | ||
2076 | } | ||
2077 | |||
2078 | case JSTRACE_STRING: | ||
2079 | name = JSSTRING_IS_DEPENDENT((JSString *)thing) | ||
2080 | ? "substring" | ||
2081 | : "string"; | ||
2082 | break; | ||
2083 | |||
2084 | case JSTRACE_DOUBLE: | ||
2085 | name = "double"; | ||
2086 | break; | ||
2087 | |||
2088 | #if JS_HAS_XML_SUPPORT | ||
2089 | case JSTRACE_XML: | ||
2090 | name = "xml"; | ||
2091 | break; | ||
2092 | #endif | ||
2093 | default: | ||
2094 | JS_ASSERT(0); | ||
2095 | return; | ||
2096 | break; | ||
2097 | } | ||
2098 | |||
2099 | n = strlen(name); | ||
2100 | if (n > bufsize - 1) | ||
2101 | n = bufsize - 1; | ||
2102 | memcpy(buf, name, n + 1); | ||
2103 | buf += n; | ||
2104 | bufsize -= n; | ||
2105 | |||
2106 | if (details && bufsize > 2) { | ||
2107 | *buf++ = ' '; | ||
2108 | bufsize--; | ||
2109 | |||
2110 | switch (kind) { | ||
2111 | case JSTRACE_OBJECT: | ||
2112 | { | ||
2113 | JSObject *obj = (JSObject *)thing; | ||
2114 | JSClass *clasp = STOBJ_GET_CLASS(obj); | ||
2115 | if (clasp == &js_FunctionClass) { | ||
2116 | JSFunction *fun = (JSFunction *) | ||
2117 | JS_GetPrivate(trc->context, obj); | ||
2118 | |||
2119 | if (!fun) { | ||
2120 | JS_snprintf(buf, bufsize, "<newborn>"); | ||
2121 | } else if (FUN_OBJECT(fun) != obj) { | ||
2122 | JS_snprintf(buf, bufsize, "%p", fun); | ||
2123 | } else { | ||
2124 | if (fun->atom && ATOM_IS_STRING(fun->atom)) | ||
2125 | js_PutEscapedString(buf, bufsize, | ||
2126 | ATOM_TO_STRING(fun->atom), 0); | ||
2127 | } | ||
2128 | } else if (clasp->flags & JSCLASS_HAS_PRIVATE) { | ||
2129 | jsval privateValue = STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE); | ||
2130 | void *privateThing = JSVAL_IS_VOID(privateValue) | ||
2131 | ? NULL | ||
2132 | : JSVAL_TO_PRIVATE(privateValue); | ||
2133 | |||
2134 | JS_snprintf(buf, bufsize, "%p", privateThing); | ||
2135 | } else { | ||
2136 | JS_snprintf(buf, bufsize, "<no private>"); | ||
2137 | } | ||
2138 | break; | ||
2139 | } | ||
2140 | |||
2141 | case JSTRACE_STRING: | ||
2142 | js_PutEscapedString(buf, bufsize, (JSString *)thing, 0); | ||
2143 | break; | ||
2144 | |||
2145 | case JSTRACE_DOUBLE: | ||
2146 | JS_snprintf(buf, bufsize, "%g", *(jsdouble *)thing); | ||
2147 | break; | ||
2148 | |||
2149 | #if JS_HAS_XML_SUPPORT | ||
2150 | case JSTRACE_XML: | ||
2151 | { | ||
2152 | extern const char *js_xml_class_str[]; | ||
2153 | JSXML *xml = (JSXML *)thing; | ||
2154 | |||
2155 | JS_snprintf(buf, bufsize, "%s", js_xml_class_str[xml->xml_class]); | ||
2156 | break; | ||
2157 | } | ||
2158 | #endif | ||
2159 | default: | ||
2160 | JS_ASSERT(0); | ||
2161 | break; | ||
2162 | } | ||
2163 | } | ||
2164 | buf[bufsize - 1] = '\0'; | ||
2165 | } | ||
2166 | |||
2167 | typedef struct JSHeapDumpNode JSHeapDumpNode; | ||
2168 | |||
2169 | struct JSHeapDumpNode { | ||
2170 | void *thing; | ||
2171 | uint32 kind; | ||
2172 | JSHeapDumpNode *next; /* next sibling */ | ||
2173 | JSHeapDumpNode *parent; /* node with the thing that refer to thing | ||
2174 | from this node */ | ||
2175 | char edgeName[1]; /* name of the edge from parent->thing | ||
2176 | into thing */ | ||
2177 | }; | ||
2178 | |||
2179 | typedef struct JSDumpingTracer { | ||
2180 | JSTracer base; | ||
2181 | JSDHashTable visited; | ||
2182 | JSBool ok; | ||
2183 | void *startThing; | ||
2184 | void *thingToFind; | ||
2185 | void *thingToIgnore; | ||
2186 | JSHeapDumpNode *parentNode; | ||
2187 | JSHeapDumpNode **lastNodep; | ||
2188 | char buffer[200]; | ||
2189 | } JSDumpingTracer; | ||
2190 | |||
2191 | static void | ||
2192 | DumpNotify(JSTracer *trc, void *thing, uint32 kind) | ||
2193 | { | ||
2194 | JSDumpingTracer *dtrc; | ||
2195 | JSContext *cx; | ||
2196 | JSDHashEntryStub *entry; | ||
2197 | JSHeapDumpNode *node; | ||
2198 | const char *edgeName; | ||
2199 | size_t edgeNameSize; | ||
2200 | |||
2201 | JS_ASSERT(trc->callback == DumpNotify); | ||
2202 | dtrc = (JSDumpingTracer *)trc; | ||
2203 | |||
2204 | if (!dtrc->ok || thing == dtrc->thingToIgnore) | ||
2205 | return; | ||
2206 | |||
2207 | cx = trc->context; | ||
2208 | |||
2209 | /* | ||
2210 | * Check if we have already seen thing unless it is thingToFind to include | ||
2211 | * it to the graph each time we reach it and print all live things that | ||
2212 | * refer to thingToFind. | ||
2213 | * | ||
2214 | * This does not print all possible paths leading to thingToFind since | ||
2215 | * when a thing A refers directly or indirectly to thingToFind and A is | ||
2216 | * present several times in the graph, we will print only the first path | ||
2217 | * leading to A and thingToFind, other ways to reach A will be ignored. | ||
2218 | */ | ||
2219 | if (dtrc->thingToFind != thing) { | ||
2220 | /* | ||
2221 | * The startThing check allows to avoid putting startThing into the | ||
2222 | * hash table before tracing startThing in JS_DumpHeap. | ||
2223 | */ | ||
2224 | if (thing == dtrc->startThing) | ||
2225 | return; | ||
2226 | entry = (JSDHashEntryStub *) | ||
2227 | JS_DHashTableOperate(&dtrc->visited, thing, JS_DHASH_ADD); | ||
2228 | if (!entry) { | ||
2229 | JS_ReportOutOfMemory(cx); | ||
2230 | dtrc->ok = JS_FALSE; | ||
2231 | return; | ||
2232 | } | ||
2233 | if (entry->key) | ||
2234 | return; | ||
2235 | entry->key = thing; | ||
2236 | } | ||
2237 | |||
2238 | if (dtrc->base.debugPrinter) { | ||
2239 | dtrc->base.debugPrinter(trc, dtrc->buffer, sizeof(dtrc->buffer)); | ||
2240 | edgeName = dtrc->buffer; | ||
2241 | } else if (dtrc->base.debugPrintIndex != (size_t)-1) { | ||
2242 | JS_snprintf(dtrc->buffer, sizeof(dtrc->buffer), "%s[%lu]", | ||
2243 | (const char *)dtrc->base.debugPrintArg, | ||
2244 | dtrc->base.debugPrintIndex); | ||
2245 | edgeName = dtrc->buffer; | ||
2246 | } else { | ||
2247 | edgeName = (const char*)dtrc->base.debugPrintArg; | ||
2248 | } | ||
2249 | |||
2250 | edgeNameSize = strlen(edgeName) + 1; | ||
2251 | node = (JSHeapDumpNode *) | ||
2252 | JS_malloc(cx, offsetof(JSHeapDumpNode, edgeName) + edgeNameSize); | ||
2253 | if (!node) { | ||
2254 | dtrc->ok = JS_FALSE; | ||
2255 | return; | ||
2256 | } | ||
2257 | |||
2258 | node->thing = thing; | ||
2259 | node->kind = kind; | ||
2260 | node->next = NULL; | ||
2261 | node->parent = dtrc->parentNode; | ||
2262 | memcpy(node->edgeName, edgeName, edgeNameSize); | ||
2263 | |||
2264 | JS_ASSERT(!*dtrc->lastNodep); | ||
2265 | *dtrc->lastNodep = node; | ||
2266 | dtrc->lastNodep = &node->next; | ||
2267 | } | ||
2268 | |||
2269 | /* Dump node and the chain that leads to thing it contains. */ | ||
2270 | static JSBool | ||
2271 | DumpNode(JSDumpingTracer *dtrc, FILE* fp, JSHeapDumpNode *node) | ||
2272 | { | ||
2273 | JSHeapDumpNode *prev, *following; | ||
2274 | size_t chainLimit; | ||
2275 | JSBool ok; | ||
2276 | enum { MAX_PARENTS_TO_PRINT = 10 }; | ||
2277 | |||
2278 | JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer, | ||
2279 | &dtrc->base, node->thing, node->kind, JS_TRUE); | ||
2280 | if (fprintf(fp, "%p %-22s via ", node->thing, dtrc->buffer) < 0) | ||
2281 | return JS_FALSE; | ||
2282 | |||
2283 | /* | ||
2284 | * We need to print the parent chain in the reverse order. To do it in | ||
2285 | * O(N) time where N is the chain length we first reverse the chain while | ||
2286 | * searching for the top and then print each node while restoring the | ||
2287 | * chain order. | ||
2288 | */ | ||
2289 | chainLimit = MAX_PARENTS_TO_PRINT; | ||
2290 | prev = NULL; | ||
2291 | for (;;) { | ||
2292 | following = node->parent; | ||
2293 | node->parent = prev; | ||
2294 | prev = node; | ||
2295 | node = following; | ||
2296 | if (!node) | ||
2297 | break; | ||
2298 | if (chainLimit == 0) { | ||
2299 | if (fputs("...", fp) < 0) | ||
2300 | return JS_FALSE; | ||
2301 | break; | ||
2302 | } | ||
2303 | --chainLimit; | ||
2304 | } | ||
2305 | |||
2306 | node = prev; | ||
2307 | prev = following; | ||
2308 | ok = JS_TRUE; | ||
2309 | do { | ||
2310 | /* Loop must continue even when !ok to restore the parent chain. */ | ||
2311 | if (ok) { | ||
2312 | if (!prev) { | ||
2313 | /* Print edge from some runtime root or startThing. */ | ||
2314 | if (fputs(node->edgeName, fp) < 0) | ||
2315 | ok = JS_FALSE; | ||
2316 | } else { | ||
2317 | JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer, | ||
2318 | &dtrc->base, prev->thing, prev->kind, | ||
2319 | JS_FALSE); | ||
2320 | if (fprintf(fp, "(%p %s).%s", | ||
2321 | prev->thing, dtrc->buffer, node->edgeName) < 0) { | ||
2322 | ok = JS_FALSE; | ||
2323 | } | ||
2324 | } | ||
2325 | } | ||
2326 | following = node->parent; | ||
2327 | node->parent = prev; | ||
2328 | prev = node; | ||
2329 | node = following; | ||
2330 | } while (node); | ||
2331 | |||
2332 | return ok && putc('\n', fp) >= 0; | ||
2333 | } | ||
2334 | |||
2335 | JS_PUBLIC_API(JSBool) | ||
2336 | JS_DumpHeap(JSContext *cx, FILE *fp, void* startThing, uint32 startKind, | ||
2337 | void *thingToFind, size_t maxDepth, void *thingToIgnore) | ||
2338 | { | ||
2339 | JSDumpingTracer dtrc; | ||
2340 | JSHeapDumpNode *node, *children, *next, *parent; | ||
2341 | size_t depth; | ||
2342 | JSBool thingToFindWasTraced; | ||
2343 | |||
2344 | if (maxDepth == 0) | ||
2345 | return JS_TRUE; | ||
2346 | |||
2347 | JS_TRACER_INIT(&dtrc.base, cx, DumpNotify); | ||
2348 | if (!JS_DHashTableInit(&dtrc.visited, JS_DHashGetStubOps(), | ||
2349 | NULL, sizeof(JSDHashEntryStub), | ||
2350 | JS_DHASH_DEFAULT_CAPACITY(100))) { | ||
2351 | JS_ReportOutOfMemory(cx); | ||
2352 | return JS_FALSE; | ||
2353 | } | ||
2354 | dtrc.ok = JS_TRUE; | ||
2355 | dtrc.startThing = startThing; | ||
2356 | dtrc.thingToFind = thingToFind; | ||
2357 | dtrc.thingToIgnore = thingToIgnore; | ||
2358 | dtrc.parentNode = NULL; | ||
2359 | node = NULL; | ||
2360 | dtrc.lastNodep = &node; | ||
2361 | if (!startThing) { | ||
2362 | JS_ASSERT(startKind == 0); | ||
2363 | JS_TraceRuntime(&dtrc.base); | ||
2364 | } else { | ||
2365 | JS_TraceChildren(&dtrc.base, startThing, startKind); | ||
2366 | } | ||
2367 | |||
2368 | depth = 1; | ||
2369 | if (!node) | ||
2370 | goto dump_out; | ||
2371 | |||
2372 | thingToFindWasTraced = thingToFind && thingToFind == startThing; | ||
2373 | for (;;) { | ||
2374 | /* | ||
2375 | * Loop must continue even when !dtrc.ok to free all nodes allocated | ||
2376 | * so far. | ||
2377 | */ | ||
2378 | if (dtrc.ok) { | ||
2379 | if (thingToFind == NULL || thingToFind == node->thing) | ||
2380 | dtrc.ok = DumpNode(&dtrc, fp, node); | ||
2381 | |||
2382 | /* Descend into children. */ | ||
2383 | if (dtrc.ok && | ||
2384 | depth < maxDepth && | ||
2385 | (thingToFind != node->thing || !thingToFindWasTraced)) { | ||
2386 | dtrc.parentNode = node; | ||
2387 | children = NULL; | ||
2388 | dtrc.lastNodep = &children; | ||
2389 | JS_TraceChildren(&dtrc.base, node->thing, node->kind); | ||
2390 | if (thingToFind == node->thing) | ||
2391 | thingToFindWasTraced = JS_TRUE; | ||
2392 | if (children != NULL) { | ||
2393 | ++depth; | ||
2394 | node = children; | ||
2395 | continue; | ||
2396 | } | ||
2397 | } | ||
2398 | } | ||
2399 | |||
2400 | /* Move to next or parents next and free the node. */ | ||
2401 | for (;;) { | ||
2402 | next = node->next; | ||
2403 | parent = node->parent; | ||
2404 | JS_free(cx, node); | ||
2405 | node = next; | ||
2406 | if (node) | ||
2407 | break; | ||
2408 | if (!parent) | ||
2409 | goto dump_out; | ||
2410 | JS_ASSERT(depth > 1); | ||
2411 | --depth; | ||
2412 | node = parent; | ||
2413 | } | ||
2414 | } | ||
2415 | |||
2416 | dump_out: | ||
2417 | JS_ASSERT(depth == 1); | ||
2418 | JS_DHashTableFinish(&dtrc.visited); | ||
2419 | return dtrc.ok; | ||
2420 | } | ||
2421 | |||
2422 | #endif /* DEBUG */ | ||
2423 | |||
2424 | JS_PUBLIC_API(void) | ||
2425 | JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg) | ||
2426 | { | ||
2427 | JSTracer *trc; | ||
2428 | |||
2429 | trc = (JSTracer *)arg; | ||
2430 | if (!trc) | ||
2431 | trc = cx->runtime->gcMarkingTracer; | ||
2432 | else | ||
2433 | JS_ASSERT(trc == cx->runtime->gcMarkingTracer); | ||
2434 | |||
2435 | #ifdef JS_THREADSAFE | ||
2436 | JS_ASSERT(cx->runtime->gcThread == trc->context->thread); | ||
2437 | #endif | ||
2438 | JS_SET_TRACING_NAME(trc, name ? name : "unknown"); | ||
2439 | js_CallValueTracerIfGCThing(trc, (jsval)thing); | ||
2440 | } | ||
2441 | |||
2442 | extern JS_PUBLIC_API(JSBool) | ||
2443 | JS_IsGCMarkingTracer(JSTracer *trc) | ||
2444 | { | ||
2445 | return IS_GC_MARKING_TRACER(trc); | ||
2446 | } | ||
2447 | |||
2448 | JS_PUBLIC_API(void) | ||
2449 | JS_GC(JSContext *cx) | ||
2450 | { | ||
2451 | siliconforks | 460 | js_LeaveTrace(cx); |
2452 | |||
2453 | siliconforks | 332 | /* Don't nuke active arenas if executing or compiling. */ |
2454 | if (cx->stackPool.current == &cx->stackPool.first) | ||
2455 | JS_FinishArenaPool(&cx->stackPool); | ||
2456 | if (cx->tempPool.current == &cx->tempPool.first) | ||
2457 | JS_FinishArenaPool(&cx->tempPool); | ||
2458 | js_GC(cx, GC_NORMAL); | ||
2459 | } | ||
2460 | |||
2461 | JS_PUBLIC_API(void) | ||
2462 | JS_MaybeGC(JSContext *cx) | ||
2463 | { | ||
2464 | JSRuntime *rt; | ||
2465 | uint32 bytes, lastBytes; | ||
2466 | |||
2467 | rt = cx->runtime; | ||
2468 | |||
2469 | #ifdef JS_GC_ZEAL | ||
2470 | if (rt->gcZeal > 0) { | ||
2471 | JS_GC(cx); | ||
2472 | return; | ||
2473 | } | ||
2474 | #endif | ||
2475 | |||
2476 | bytes = rt->gcBytes; | ||
2477 | lastBytes = rt->gcLastBytes; | ||
2478 | |||
2479 | /* | ||
2480 | * We run the GC if we used all available free GC cells and had to | ||
2481 | * allocate extra 1/3 of GC arenas since the last run of GC, or if | ||
2482 | * we have malloc'd more bytes through JS_malloc than we were told | ||
2483 | * to allocate by JS_NewRuntime. | ||
2484 | * | ||
2485 | * The reason for | ||
2486 | * bytes > 4/3 lastBytes | ||
2487 | * condition is the following. Bug 312238 changed bytes and lastBytes | ||
2488 | * to mean the total amount of memory that the GC uses now and right | ||
2489 | * after the last GC. | ||
2490 | * | ||
2491 | * Before the bug the variables meant the size of allocated GC things | ||
2492 | * now and right after the last GC. That size did not include the | ||
2493 | * memory taken by free GC cells and the condition was | ||
2494 | * bytes > 3/2 lastBytes. | ||
2495 | * That is, we run the GC if we have half again as many bytes of | ||
2496 | * GC-things as the last time we GC'd. To be compatible we need to | ||
2497 | * express that condition through the new meaning of bytes and | ||
2498 | * lastBytes. | ||
2499 | * | ||
2500 | * We write the original condition as | ||
2501 | * B*(1-F) > 3/2 Bl*(1-Fl) | ||
2502 | * where B is the total memory size allocated by GC and F is the free | ||
2503 | * cell density currently and Sl and Fl are the size and the density | ||
2504 | * right after GC. The density by definition is memory taken by free | ||
2505 | * cells divided by total amount of memory. In other words, B and Bl | ||
2506 | * are bytes and lastBytes with the new meaning and B*(1-F) and | ||
2507 | * Bl*(1-Fl) are bytes and lastBytes with the original meaning. | ||
2508 | * | ||
2509 | * Our task is to exclude F and Fl from the last statement. According | ||
2510 | * to the stats from bug 331966 comment 23, Fl is about 10-25% for a | ||
2511 | * typical run of the browser. It means that the original condition | ||
2512 | * implied that we did not run GC unless we exhausted the pool of | ||
2513 | * free cells. Indeed if we still have free cells, then B == Bl since | ||
2514 | * we did not yet allocated any new arenas and the condition means | ||
2515 | * 1 - F > 3/2 (1-Fl) or 3/2Fl > 1/2 + F | ||
2516 | siliconforks | 460 | * That implies 3/2 Fl > 1/2 or Fl > 1/3. That cannot be fulfilled |
2517 | siliconforks | 332 | * for the state described by the stats. So we can write the original |
2518 | * condition as: | ||
2519 | * F == 0 && B > 3/2 Bl(1-Fl) | ||
2520 | * Again using the stats we see that Fl is about 11% when the browser | ||
2521 | * starts up and when we are far from hitting rt->gcMaxBytes. With | ||
2522 | * this F we have | ||
2523 | * F == 0 && B > 3/2 Bl(1-0.11) | ||
2524 | * or approximately F == 0 && B > 4/3 Bl. | ||
2525 | */ | ||
2526 | if ((bytes > 8192 && bytes > lastBytes + lastBytes / 3) || | ||
2527 | rt->gcMallocBytes >= rt->gcMaxMallocBytes) { | ||
2528 | JS_GC(cx); | ||
2529 | } | ||
2530 | } | ||
2531 | |||
2532 | JS_PUBLIC_API(JSGCCallback) | ||
2533 | JS_SetGCCallback(JSContext *cx, JSGCCallback cb) | ||
2534 | { | ||
2535 | CHECK_REQUEST(cx); | ||
2536 | return JS_SetGCCallbackRT(cx->runtime, cb); | ||
2537 | } | ||
2538 | |||
2539 | JS_PUBLIC_API(JSGCCallback) | ||
2540 | JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb) | ||
2541 | { | ||
2542 | JSGCCallback oldcb; | ||
2543 | |||
2544 | oldcb = rt->gcCallback; | ||
2545 | rt->gcCallback = cb; | ||
2546 | return oldcb; | ||
2547 | } | ||
2548 | |||
2549 | JS_PUBLIC_API(JSBool) | ||
2550 | JS_IsAboutToBeFinalized(JSContext *cx, void *thing) | ||
2551 | { | ||
2552 | JS_ASSERT(thing); | ||
2553 | return js_IsAboutToBeFinalized(cx, thing); | ||
2554 | } | ||
2555 | |||
2556 | JS_PUBLIC_API(void) | ||
2557 | JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value) | ||
2558 | { | ||
2559 | switch (key) { | ||
2560 | case JSGC_MAX_BYTES: | ||
2561 | rt->gcMaxBytes = value; | ||
2562 | break; | ||
2563 | case JSGC_MAX_MALLOC_BYTES: | ||
2564 | rt->gcMaxMallocBytes = value; | ||
2565 | break; | ||
2566 | case JSGC_STACKPOOL_LIFESPAN: | ||
2567 | rt->gcEmptyArenaPoolLifespan = value; | ||
2568 | break; | ||
2569 | siliconforks | 460 | default: |
2570 | JS_ASSERT(key == JSGC_TRIGGER_FACTOR); | ||
2571 | JS_ASSERT(value >= 100); | ||
2572 | rt->gcTriggerFactor = value; | ||
2573 | return; | ||
2574 | siliconforks | 332 | } |
2575 | } | ||
2576 | |||
2577 | siliconforks | 460 | JS_PUBLIC_API(uint32) |
2578 | JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key) | ||
2579 | { | ||
2580 | switch (key) { | ||
2581 | case JSGC_MAX_BYTES: | ||
2582 | return rt->gcMaxBytes; | ||
2583 | case JSGC_MAX_MALLOC_BYTES: | ||
2584 | return rt->gcMaxMallocBytes; | ||
2585 | case JSGC_STACKPOOL_LIFESPAN: | ||
2586 | return rt->gcEmptyArenaPoolLifespan; | ||
2587 | case JSGC_TRIGGER_FACTOR: | ||
2588 | return rt->gcTriggerFactor; | ||
2589 | case JSGC_BYTES: | ||
2590 | return rt->gcBytes; | ||
2591 | default: | ||
2592 | JS_ASSERT(key == JSGC_NUMBER); | ||
2593 | return rt->gcNumber; | ||
2594 | } | ||
2595 | } | ||
2596 | |||
2597 | JS_PUBLIC_API(void) | ||
2598 | JS_SetGCParameterForThread(JSContext *cx, JSGCParamKey key, uint32 value) | ||
2599 | { | ||
2600 | JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES); | ||
2601 | #ifdef JS_TRACER | ||
2602 | js_SetMaxCodeCacheBytes(cx, value); | ||
2603 | #endif | ||
2604 | } | ||
2605 | |||
2606 | JS_PUBLIC_API(uint32) | ||
2607 | JS_GetGCParameterForThread(JSContext *cx, JSGCParamKey key) | ||
2608 | { | ||
2609 | JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES); | ||
2610 | #ifdef JS_TRACER | ||
2611 | return JS_THREAD_DATA(cx)->traceMonitor.maxCodeCacheBytes; | ||
2612 | #else | ||
2613 | return 0; | ||
2614 | #endif | ||
2615 | } | ||
2616 | |||
2617 | siliconforks | 332 | JS_PUBLIC_API(intN) |
2618 | JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer) | ||
2619 | { | ||
2620 | return js_ChangeExternalStringFinalizer(NULL, finalizer); | ||
2621 | } | ||
2622 | |||
2623 | JS_PUBLIC_API(intN) | ||
2624 | JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer) | ||
2625 | { | ||
2626 | return js_ChangeExternalStringFinalizer(finalizer, NULL); | ||
2627 | } | ||
2628 | |||
2629 | JS_PUBLIC_API(JSString *) | ||
2630 | JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type) | ||
2631 | { | ||
2632 | JSString *str; | ||
2633 | |||
2634 | CHECK_REQUEST(cx); | ||
2635 | JS_ASSERT((uintN) type < (uintN) (GCX_NTYPES - GCX_EXTERNAL_STRING)); | ||
2636 | |||
2637 | str = (JSString *) js_NewGCThing(cx, (uintN) type + GCX_EXTERNAL_STRING, | ||
2638 | sizeof(JSString)); | ||
2639 | if (!str) | ||
2640 | return NULL; | ||
2641 | JSFLATSTR_INIT(str, chars, length); | ||
2642 | return str; | ||
2643 | } | ||
2644 | |||
2645 | JS_PUBLIC_API(intN) | ||
2646 | JS_GetExternalStringGCType(JSRuntime *rt, JSString *str) | ||
2647 | { | ||
2648 | return js_GetExternalStringGCType(str); | ||
2649 | } | ||
2650 | |||
2651 | JS_PUBLIC_API(void) | ||
2652 | JS_SetThreadStackLimit(JSContext *cx, jsuword |