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