PageRenderTime 58ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/js/jsapi.cpp

http://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs
C++ | 2314 lines | 1863 code | 266 blank | 185 comment | 297 complexity | 1b4b4664355e81ed970caba93e4dbf1d MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * vim: set ts=8 sw=4 et tw=78:
  3. *
  4. * ***** BEGIN LICENSE BLOCK *****
  5. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  6. *
  7. * The contents of this file are subject to the Mozilla Public License Version
  8. * 1.1 (the "License"); you may not use this file except in compliance with
  9. * the License. You may obtain a copy of the License at
  10. * http://www.mozilla.org/MPL/
  11. *
  12. * Software distributed under the License is distributed on an "AS IS" basis,
  13. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  14. * for the specific language governing rights and limitations under the
  15. * License.
  16. *
  17. * The Original Code is Mozilla Communicator client code, released
  18. * March 31, 1998.
  19. *
  20. * The Initial Developer of the Original Code is
  21. * Netscape Communications Corporation.
  22. * Portions created by the Initial Developer are Copyright (C) 1998
  23. * the Initial Developer. All Rights Reserved.
  24. *
  25. * Contributor(s):
  26. *
  27. * Alternatively, the contents of this file may be used under the terms of
  28. * either of the GNU General Public License Version 2 or later (the "GPL"),
  29. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  30. * in which case the provisions of the GPL or the LGPL are applicable instead
  31. * of those above. If you wish to allow use of your version of this file only
  32. * under the terms of either the GPL or the LGPL, and not to allow others to
  33. * use your version of this file under the terms of the MPL, indicate your
  34. * decision by deleting the provisions above and replace them with the notice
  35. * and other provisions required by the GPL or the LGPL. If you do not delete
  36. * the provisions above, a recipient may use your version of this file under
  37. * the terms of any one of the MPL, the GPL or the LGPL.
  38. *
  39. * ***** END LICENSE BLOCK ***** */
  40. /*
  41. * JavaScript API.
  42. */
  43. #include "jsstddef.h"
  44. #include <ctype.h>
  45. #include <stdarg.h>
  46. #include <stdlib.h>
  47. #include <string.h>
  48. #include "jstypes.h"
  49. #include "jsarena.h" /* Added by JSIFY */
  50. #include "jsutil.h" /* Added by JSIFY */
  51. #include "jsclist.h"
  52. #include "jsdhash.h"
  53. #include "jsprf.h"
  54. #include "jsapi.h"
  55. #include "jsarray.h"
  56. #include "jsatom.h"
  57. #include "jsbool.h"
  58. #include "jsbuiltins.h"
  59. #include "jscntxt.h"
  60. #include "jsversion.h"
  61. #include "jsdate.h"
  62. #include "jsdtoa.h"
  63. #include "jsemit.h"
  64. #include "jsexn.h"
  65. #include "jsfun.h"
  66. #include "jsgc.h"
  67. #include "jsinterp.h"
  68. #include "jsiter.h"
  69. #include "jslock.h"
  70. #include "jsmath.h"
  71. #include "jsnum.h"
  72. #include "json.h"
  73. #include "jsobj.h"
  74. #include "jsopcode.h"
  75. #include "jsparse.h"
  76. #include "jsregexp.h"
  77. #include "jsscan.h"
  78. #include "jsscope.h"
  79. #include "jsscript.h"
  80. #include "jsstr.h"
  81. #include "prmjtime.h"
  82. #include "jsstaticcheck.h"
  83. #if !defined JS_THREADSAFE && defined JS_TRACER
  84. #include "jstracer.h"
  85. #endif
  86. #if JS_HAS_FILE_OBJECT
  87. #include "jsfile.h"
  88. #endif
  89. #if JS_HAS_XML_SUPPORT
  90. #include "jsxml.h"
  91. #endif
  92. #ifdef HAVE_VA_LIST_AS_ARRAY
  93. #define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
  94. #else
  95. #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
  96. #endif
  97. #if defined(JS_THREADSAFE)
  98. #define CHECK_REQUEST(cx) \
  99. JS_ASSERT((cx)->requestDepth || (cx)->thread == (cx)->runtime->gcThread)
  100. #else
  101. #define CHECK_REQUEST(cx) ((void)0)
  102. #endif
  103. JS_PUBLIC_API(int64)
  104. JS_Now()
  105. {
  106. return PRMJ_Now();
  107. }
  108. JS_PUBLIC_API(jsval)
  109. JS_GetNaNValue(JSContext *cx)
  110. {
  111. return DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
  112. }
  113. JS_PUBLIC_API(jsval)
  114. JS_GetNegativeInfinityValue(JSContext *cx)
  115. {
  116. return DOUBLE_TO_JSVAL(cx->runtime->jsNegativeInfinity);
  117. }
  118. JS_PUBLIC_API(jsval)
  119. JS_GetPositiveInfinityValue(JSContext *cx)
  120. {
  121. return DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
  122. }
  123. JS_PUBLIC_API(jsval)
  124. JS_GetEmptyStringValue(JSContext *cx)
  125. {
  126. return STRING_TO_JSVAL(cx->runtime->emptyString);
  127. }
  128. static JSBool
  129. TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS,
  130. jsval **vpp, va_list *app)
  131. {
  132. const char *format;
  133. JSArgumentFormatMap *map;
  134. format = *formatp;
  135. for (map = cx->argumentFormatMap; map; map = map->next) {
  136. if (!strncmp(format, map->format, map->length)) {
  137. *formatp = format + map->length;
  138. return map->formatter(cx, format, fromJS, vpp, app);
  139. }
  140. }
  141. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
  142. return JS_FALSE;
  143. }
  144. JS_PUBLIC_API(JSBool)
  145. JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format,
  146. ...)
  147. {
  148. va_list ap;
  149. JSBool ok;
  150. va_start(ap, format);
  151. ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap);
  152. va_end(ap);
  153. return ok;
  154. }
  155. JS_PUBLIC_API(JSBool)
  156. JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv,
  157. const char *format, va_list ap)
  158. {
  159. jsval *sp;
  160. JSBool required;
  161. char c;
  162. JSFunction *fun;
  163. jsdouble d;
  164. JSString *str;
  165. JSObject *obj;
  166. CHECK_REQUEST(cx);
  167. sp = argv;
  168. required = JS_TRUE;
  169. while ((c = *format++) != '\0') {
  170. if (isspace(c))
  171. continue;
  172. if (c == '/') {
  173. required = JS_FALSE;
  174. continue;
  175. }
  176. if (sp == argv + argc) {
  177. if (required) {
  178. fun = js_ValueToFunction(cx, &argv[-2], 0);
  179. if (fun) {
  180. char numBuf[12];
  181. JS_snprintf(numBuf, sizeof numBuf, "%u", argc);
  182. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
  183. JSMSG_MORE_ARGS_NEEDED,
  184. JS_GetFunctionName(fun), numBuf,
  185. (argc == 1) ? "" : "s");
  186. }
  187. return JS_FALSE;
  188. }
  189. break;
  190. }
  191. switch (c) {
  192. case 'b':
  193. *va_arg(ap, JSBool *) = js_ValueToBoolean(*sp);
  194. break;
  195. case 'c':
  196. if (!JS_ValueToUint16(cx, *sp, va_arg(ap, uint16 *)))
  197. return JS_FALSE;
  198. break;
  199. case 'i':
  200. if (!JS_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *)))
  201. return JS_FALSE;
  202. break;
  203. case 'u':
  204. if (!JS_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *)))
  205. return JS_FALSE;
  206. break;
  207. case 'j':
  208. if (!JS_ValueToInt32(cx, *sp, va_arg(ap, int32 *)))
  209. return JS_FALSE;
  210. break;
  211. case 'd':
  212. if (!JS_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *)))
  213. return JS_FALSE;
  214. break;
  215. case 'I':
  216. if (!JS_ValueToNumber(cx, *sp, &d))
  217. return JS_FALSE;
  218. *va_arg(ap, jsdouble *) = js_DoubleToInteger(d);
  219. break;
  220. case 's':
  221. case 'S':
  222. case 'W':
  223. str = js_ValueToString(cx, *sp);
  224. if (!str)
  225. return JS_FALSE;
  226. *sp = STRING_TO_JSVAL(str);
  227. if (c == 's') {
  228. const char *bytes = js_GetStringBytes(cx, str);
  229. if (!bytes)
  230. return JS_FALSE;
  231. *va_arg(ap, const char **) = bytes;
  232. } else if (c == 'W') {
  233. const jschar *chars = js_GetStringChars(cx, str);
  234. if (!chars)
  235. return JS_FALSE;
  236. *va_arg(ap, const jschar **) = chars;
  237. } else {
  238. *va_arg(ap, JSString **) = str;
  239. }
  240. break;
  241. case 'o':
  242. if (!js_ValueToObject(cx, *sp, &obj))
  243. return JS_FALSE;
  244. *sp = OBJECT_TO_JSVAL(obj);
  245. *va_arg(ap, JSObject **) = obj;
  246. break;
  247. case 'f':
  248. obj = js_ValueToFunctionObject(cx, sp, 0);
  249. if (!obj)
  250. return JS_FALSE;
  251. *sp = OBJECT_TO_JSVAL(obj);
  252. *va_arg(ap, JSFunction **) = (JSFunction *) JS_GetPrivate(cx, obj);
  253. break;
  254. case 'v':
  255. *va_arg(ap, jsval *) = *sp;
  256. break;
  257. case '*':
  258. break;
  259. default:
  260. format--;
  261. if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp,
  262. JS_ADDRESSOF_VA_LIST(ap))) {
  263. return JS_FALSE;
  264. }
  265. /* NB: the formatter already updated sp, so we continue here. */
  266. continue;
  267. }
  268. sp++;
  269. }
  270. return JS_TRUE;
  271. }
  272. JS_PUBLIC_API(jsval *)
  273. JS_PushArguments(JSContext *cx, void **markp, const char *format, ...)
  274. {
  275. va_list ap;
  276. jsval *argv;
  277. va_start(ap, format);
  278. argv = JS_PushArgumentsVA(cx, markp, format, ap);
  279. va_end(ap);
  280. return argv;
  281. }
  282. JS_PUBLIC_API(jsval *)
  283. JS_PushArgumentsVA(JSContext *cx, void **markp, const char *format, va_list ap)
  284. {
  285. uintN argc;
  286. jsval *argv, *sp;
  287. char c;
  288. const char *cp;
  289. JSString *str;
  290. JSFunction *fun;
  291. JSStackHeader *sh;
  292. CHECK_REQUEST(cx);
  293. *markp = NULL;
  294. argc = 0;
  295. for (cp = format; (c = *cp) != '\0'; cp++) {
  296. /*
  297. * Count non-space non-star characters as individual jsval arguments.
  298. * This may over-allocate stack, but we'll fix below.
  299. */
  300. if (isspace(c) || c == '*')
  301. continue;
  302. argc++;
  303. }
  304. sp = js_AllocStack(cx, argc, markp);
  305. if (!sp)
  306. return NULL;
  307. argv = sp;
  308. while ((c = *format++) != '\0') {
  309. if (isspace(c) || c == '*')
  310. continue;
  311. switch (c) {
  312. case 'b':
  313. *sp = BOOLEAN_TO_JSVAL((JSBool) va_arg(ap, int));
  314. break;
  315. case 'c':
  316. *sp = INT_TO_JSVAL((uint16) va_arg(ap, unsigned int));
  317. break;
  318. case 'i':
  319. case 'j':
  320. /*
  321. * Use JS_New{Double,Number}Value here and in the next two cases,
  322. * not js_New{Double,Number}InRootedValue, as sp may point to an
  323. * unrooted location.
  324. */
  325. if (!JS_NewNumberValue(cx, (jsdouble) va_arg(ap, int32), sp))
  326. goto bad;
  327. break;
  328. case 'u':
  329. if (!JS_NewNumberValue(cx, (jsdouble) va_arg(ap, uint32), sp))
  330. goto bad;
  331. break;
  332. case 'd':
  333. case 'I':
  334. if (!JS_NewDoubleValue(cx, va_arg(ap, jsdouble), sp))
  335. goto bad;
  336. break;
  337. case 's':
  338. str = JS_NewStringCopyZ(cx, va_arg(ap, char *));
  339. if (!str)
  340. goto bad;
  341. *sp = STRING_TO_JSVAL(str);
  342. break;
  343. case 'W':
  344. str = JS_NewUCStringCopyZ(cx, va_arg(ap, jschar *));
  345. if (!str)
  346. goto bad;
  347. *sp = STRING_TO_JSVAL(str);
  348. break;
  349. case 'S':
  350. str = va_arg(ap, JSString *);
  351. *sp = STRING_TO_JSVAL(str);
  352. break;
  353. case 'o':
  354. *sp = OBJECT_TO_JSVAL(va_arg(ap, JSObject *));
  355. break;
  356. case 'f':
  357. fun = va_arg(ap, JSFunction *);
  358. *sp = fun ? OBJECT_TO_JSVAL(FUN_OBJECT(fun)) : JSVAL_NULL;
  359. break;
  360. case 'v':
  361. *sp = va_arg(ap, jsval);
  362. break;
  363. default:
  364. format--;
  365. if (!TryArgumentFormatter(cx, &format, JS_FALSE, &sp,
  366. JS_ADDRESSOF_VA_LIST(ap))) {
  367. goto bad;
  368. }
  369. /* NB: the formatter already updated sp, so we continue here. */
  370. continue;
  371. }
  372. sp++;
  373. }
  374. /*
  375. * We may have overallocated stack due to a multi-character format code
  376. * handled by a JSArgumentFormatter. Give back that stack space!
  377. */
  378. JS_ASSERT(sp <= argv + argc);
  379. if (sp < argv + argc) {
  380. /* Return slots not pushed to the current stack arena. */
  381. cx->stackPool.current->avail = (jsuword)sp;
  382. /* Reduce the count of slots the GC will scan in this stack segment. */
  383. sh = cx->stackHeaders;
  384. JS_ASSERT(JS_STACK_SEGMENT(sh) + sh->nslots == argv + argc);
  385. sh->nslots -= argc - (sp - argv);
  386. }
  387. return argv;
  388. bad:
  389. js_FreeStack(cx, *markp);
  390. return NULL;
  391. }
  392. JS_PUBLIC_API(void)
  393. JS_PopArguments(JSContext *cx, void *mark)
  394. {
  395. CHECK_REQUEST(cx);
  396. js_FreeStack(cx, mark);
  397. }
  398. JS_PUBLIC_API(JSBool)
  399. JS_AddArgumentFormatter(JSContext *cx, const char *format,
  400. JSArgumentFormatter formatter)
  401. {
  402. size_t length;
  403. JSArgumentFormatMap **mpp, *map;
  404. length = strlen(format);
  405. mpp = &cx->argumentFormatMap;
  406. while ((map = *mpp) != NULL) {
  407. /* Insert before any shorter string to match before prefixes. */
  408. if (map->length < length)
  409. break;
  410. if (map->length == length && !strcmp(map->format, format))
  411. goto out;
  412. mpp = &map->next;
  413. }
  414. map = (JSArgumentFormatMap *) JS_malloc(cx, sizeof *map);
  415. if (!map)
  416. return JS_FALSE;
  417. map->format = format;
  418. map->length = length;
  419. map->next = *mpp;
  420. *mpp = map;
  421. out:
  422. map->formatter = formatter;
  423. return JS_TRUE;
  424. }
  425. JS_PUBLIC_API(void)
  426. JS_RemoveArgumentFormatter(JSContext *cx, const char *format)
  427. {
  428. size_t length;
  429. JSArgumentFormatMap **mpp, *map;
  430. length = strlen(format);
  431. mpp = &cx->argumentFormatMap;
  432. while ((map = *mpp) != NULL) {
  433. if (map->length == length && !strcmp(map->format, format)) {
  434. *mpp = map->next;
  435. JS_free(cx, map);
  436. return;
  437. }
  438. mpp = &map->next;
  439. }
  440. }
  441. JS_PUBLIC_API(JSBool)
  442. JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
  443. {
  444. JSBool ok;
  445. JSObject *obj;
  446. JSString *str;
  447. jsdouble d, *dp;
  448. CHECK_REQUEST(cx);
  449. switch (type) {
  450. case JSTYPE_VOID:
  451. *vp = JSVAL_VOID;
  452. ok = JS_TRUE;
  453. break;
  454. case JSTYPE_OBJECT:
  455. ok = js_ValueToObject(cx, v, &obj);
  456. if (ok)
  457. *vp = OBJECT_TO_JSVAL(obj);
  458. break;
  459. case JSTYPE_FUNCTION:
  460. *vp = v;
  461. obj = js_ValueToFunctionObject(cx, vp, JSV2F_SEARCH_STACK);
  462. ok = (obj != NULL);
  463. break;
  464. case JSTYPE_STRING:
  465. str = js_ValueToString(cx, v);
  466. ok = (str != NULL);
  467. if (ok)
  468. *vp = STRING_TO_JSVAL(str);
  469. break;
  470. case JSTYPE_NUMBER:
  471. ok = JS_ValueToNumber(cx, v, &d);
  472. if (ok) {
  473. dp = js_NewWeaklyRootedDouble(cx, d);
  474. ok = (dp != NULL);
  475. if (ok)
  476. *vp = DOUBLE_TO_JSVAL(dp);
  477. }
  478. break;
  479. case JSTYPE_BOOLEAN:
  480. *vp = BOOLEAN_TO_JSVAL(js_ValueToBoolean(v));
  481. return JS_TRUE;
  482. default: {
  483. char numBuf[12];
  484. JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
  485. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE,
  486. numBuf);
  487. ok = JS_FALSE;
  488. break;
  489. }
  490. }
  491. return ok;
  492. }
  493. JS_PUBLIC_API(JSBool)
  494. JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp)
  495. {
  496. CHECK_REQUEST(cx);
  497. return js_ValueToObject(cx, v, objp);
  498. }
  499. JS_PUBLIC_API(JSFunction *)
  500. JS_ValueToFunction(JSContext *cx, jsval v)
  501. {
  502. CHECK_REQUEST(cx);
  503. return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
  504. }
  505. JS_PUBLIC_API(JSFunction *)
  506. JS_ValueToConstructor(JSContext *cx, jsval v)
  507. {
  508. CHECK_REQUEST(cx);
  509. return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
  510. }
  511. JS_PUBLIC_API(JSString *)
  512. JS_ValueToString(JSContext *cx, jsval v)
  513. {
  514. CHECK_REQUEST(cx);
  515. return js_ValueToString(cx, v);
  516. }
  517. JS_PUBLIC_API(JSString *)
  518. JS_ValueToSource(JSContext *cx, jsval v)
  519. {
  520. CHECK_REQUEST(cx);
  521. return js_ValueToSource(cx, v);
  522. }
  523. JS_PUBLIC_API(JSBool)
  524. JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
  525. {
  526. JSTempValueRooter tvr;
  527. CHECK_REQUEST(cx);
  528. JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
  529. *dp = js_ValueToNumber(cx, &tvr.u.value);
  530. JS_POP_TEMP_ROOT(cx, &tvr);
  531. return !JSVAL_IS_NULL(tvr.u.value);
  532. }
  533. JS_PUBLIC_API(JSBool)
  534. JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
  535. {
  536. JSTempValueRooter tvr;
  537. CHECK_REQUEST(cx);
  538. JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
  539. *ip = js_ValueToECMAInt32(cx, &tvr.u.value);
  540. JS_POP_TEMP_ROOT(cx, &tvr);
  541. return !JSVAL_IS_NULL(tvr.u.value);
  542. }
  543. JS_PUBLIC_API(JSBool)
  544. JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
  545. {
  546. JSTempValueRooter tvr;
  547. CHECK_REQUEST(cx);
  548. JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
  549. *ip = js_ValueToECMAUint32(cx, &tvr.u.value);
  550. JS_POP_TEMP_ROOT(cx, &tvr);
  551. return !JSVAL_IS_NULL(tvr.u.value);
  552. }
  553. JS_PUBLIC_API(JSBool)
  554. JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
  555. {
  556. JSTempValueRooter tvr;
  557. CHECK_REQUEST(cx);
  558. JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
  559. *ip = js_ValueToInt32(cx, &tvr.u.value);
  560. JS_POP_TEMP_ROOT(cx, &tvr);
  561. return !JSVAL_IS_NULL(tvr.u.value);
  562. }
  563. JS_PUBLIC_API(JSBool)
  564. JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
  565. {
  566. JSTempValueRooter tvr;
  567. CHECK_REQUEST(cx);
  568. JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
  569. *ip = js_ValueToUint16(cx, &tvr.u.value);
  570. JS_POP_TEMP_ROOT(cx, &tvr);
  571. return !JSVAL_IS_NULL(tvr.u.value);
  572. }
  573. JS_PUBLIC_API(JSBool)
  574. JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
  575. {
  576. CHECK_REQUEST(cx);
  577. *bp = js_ValueToBoolean(v);
  578. return JS_TRUE;
  579. }
  580. JS_PUBLIC_API(JSType)
  581. JS_TypeOfValue(JSContext *cx, jsval v)
  582. {
  583. JSType type;
  584. JSObject *obj;
  585. JSObjectOps *ops;
  586. JSClass *clasp;
  587. CHECK_REQUEST(cx);
  588. if (JSVAL_IS_OBJECT(v)) {
  589. type = JSTYPE_OBJECT; /* XXXbe JSTYPE_NULL for JS2 */
  590. obj = JSVAL_TO_OBJECT(v);
  591. if (obj) {
  592. JSObject *wrapped;
  593. wrapped = js_GetWrappedObject(cx, obj);
  594. if (wrapped)
  595. obj = wrapped;
  596. ops = obj->map->ops;
  597. #if JS_HAS_XML_SUPPORT
  598. if (ops == &js_XMLObjectOps.base) {
  599. type = JSTYPE_XML;
  600. } else
  601. #endif
  602. {
  603. /*
  604. * ECMA 262, 11.4.3 says that any native object that implements
  605. * [[Call]] should be of type "function". Note that RegExp and
  606. * Script are both of type "function" for compatibility with
  607. * older SpiderMonkeys.
  608. */
  609. clasp = OBJ_GET_CLASS(cx, obj);
  610. if ((ops == &js_ObjectOps)
  611. ? (clasp->call
  612. ? clasp == &js_ScriptClass
  613. : clasp == &js_FunctionClass)
  614. : ops->call != NULL) {
  615. type = JSTYPE_FUNCTION;
  616. } else {
  617. #ifdef NARCISSUS
  618. JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
  619. if (!OBJ_GET_PROPERTY(cx, obj,
  620. ATOM_TO_JSID(cx->runtime->atomState
  621. .__call__Atom),
  622. &v)) {
  623. JS_ClearPendingException(cx);
  624. } else if (VALUE_IS_FUNCTION(cx, v)) {
  625. type = JSTYPE_FUNCTION;
  626. }
  627. #endif
  628. }
  629. }
  630. }
  631. } else if (JSVAL_IS_NUMBER(v)) {
  632. type = JSTYPE_NUMBER;
  633. } else if (JSVAL_IS_STRING(v)) {
  634. type = JSTYPE_STRING;
  635. } else if (JSVAL_IS_BOOLEAN(v)) {
  636. type = JSTYPE_BOOLEAN;
  637. } else {
  638. type = JSTYPE_VOID;
  639. }
  640. return type;
  641. }
  642. JS_PUBLIC_API(const char *)
  643. JS_GetTypeName(JSContext *cx, JSType type)
  644. {
  645. if ((uintN)type >= (uintN)JSTYPE_LIMIT)
  646. return NULL;
  647. return JS_TYPE_STR(type);
  648. }
  649. /************************************************************************/
  650. /*
  651. * Has a new runtime ever been created? This flag is used to detect unsafe
  652. * changes to js_CStringsAreUTF8 after a runtime has been created, and to
  653. * ensure that "first checks" on runtime creation are run only once.
  654. */
  655. #ifdef DEBUG
  656. static JSBool js_NewRuntimeWasCalled = JS_FALSE;
  657. #endif
  658. JS_PUBLIC_API(JSRuntime *)
  659. JS_NewRuntime(uint32 maxbytes)
  660. {
  661. JSRuntime *rt;
  662. #ifdef DEBUG
  663. if (!js_NewRuntimeWasCalled) {
  664. /*
  665. * This code asserts that the numbers associated with the error names
  666. * in jsmsg.def are monotonically increasing. It uses values for the
  667. * error names enumerated in jscntxt.c. It's not a compile-time check
  668. * but it's better than nothing.
  669. */
  670. int errorNumber = 0;
  671. #define MSG_DEF(name, number, count, exception, format) \
  672. JS_ASSERT(name == errorNumber++);
  673. #include "js.msg"
  674. #undef MSG_DEF
  675. #define MSG_DEF(name, number, count, exception, format) \
  676. JS_BEGIN_MACRO \
  677. uintN numfmtspecs = 0; \
  678. const char *fmt; \
  679. for (fmt = format; *fmt != '\0'; fmt++) { \
  680. if (*fmt == '{' && isdigit(fmt[1])) \
  681. ++numfmtspecs; \
  682. } \
  683. JS_ASSERT(count == numfmtspecs); \
  684. JS_END_MACRO;
  685. #include "js.msg"
  686. #undef MSG_DEF
  687. js_NewRuntimeWasCalled = JS_TRUE;
  688. }
  689. #endif /* DEBUG */
  690. rt = (JSRuntime *) malloc(sizeof(JSRuntime));
  691. if (!rt)
  692. return NULL;
  693. /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
  694. memset(rt, 0, sizeof(JSRuntime));
  695. JS_INIT_CLIST(&rt->contextList);
  696. JS_INIT_CLIST(&rt->trapList);
  697. JS_INIT_CLIST(&rt->watchPointList);
  698. if (!js_InitDtoa())
  699. goto bad;
  700. if (!js_InitGC(rt, maxbytes))
  701. goto bad;
  702. if (!js_InitAtomState(rt))
  703. goto bad;
  704. if (!js_InitDeflatedStringCache(rt))
  705. goto bad;
  706. #ifdef JS_THREADSAFE
  707. if (!js_InitThreadPrivateIndex(js_ThreadDestructorCB))
  708. goto bad;
  709. rt->gcLock = JS_NEW_LOCK();
  710. if (!rt->gcLock)
  711. goto bad;
  712. rt->gcDone = JS_NEW_CONDVAR(rt->gcLock);
  713. if (!rt->gcDone)
  714. goto bad;
  715. rt->requestDone = JS_NEW_CONDVAR(rt->gcLock);
  716. if (!rt->requestDone)
  717. goto bad;
  718. /* this is asymmetric with JS_ShutDown: */
  719. if (!js_SetupLocks(8, 16))
  720. goto bad;
  721. rt->rtLock = JS_NEW_LOCK();
  722. if (!rt->rtLock)
  723. goto bad;
  724. rt->stateChange = JS_NEW_CONDVAR(rt->gcLock);
  725. if (!rt->stateChange)
  726. goto bad;
  727. rt->titleSharingDone = JS_NEW_CONDVAR(rt->gcLock);
  728. if (!rt->titleSharingDone)
  729. goto bad;
  730. rt->titleSharingTodo = NO_TITLE_SHARING_TODO;
  731. rt->debuggerLock = JS_NEW_LOCK();
  732. if (!rt->debuggerLock)
  733. goto bad;
  734. #endif
  735. if (!js_InitPropertyTree(rt))
  736. goto bad;
  737. #if !defined JS_THREADSAFE && defined JS_TRACER
  738. js_InitJIT(&rt->traceMonitor);
  739. #endif
  740. return rt;
  741. bad:
  742. JS_DestroyRuntime(rt);
  743. return NULL;
  744. }
  745. JS_PUBLIC_API(void)
  746. JS_DestroyRuntime(JSRuntime *rt)
  747. {
  748. #ifdef DEBUG
  749. /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */
  750. if (!JS_CLIST_IS_EMPTY(&rt->contextList)) {
  751. JSContext *cx, *iter = NULL;
  752. uintN cxcount = 0;
  753. while ((cx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL) {
  754. fprintf(stderr,
  755. "JS API usage error: found live context at %p\n",
  756. cx);
  757. cxcount++;
  758. }
  759. fprintf(stderr,
  760. "JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n",
  761. cxcount, (cxcount == 1) ? "" : "s");
  762. }
  763. #endif
  764. #if !defined JS_THREADSAFE && defined JS_TRACER
  765. js_FinishJIT(&rt->traceMonitor);
  766. #endif
  767. js_FreeRuntimeScriptState(rt);
  768. js_FinishAtomState(rt);
  769. /*
  770. * Free unit string storage only after all strings have been finalized, so
  771. * that js_FinalizeString can detect unit strings and avoid calling free
  772. * on their chars storage.
  773. */
  774. js_FinishUnitStrings(rt);
  775. /*
  776. * Finish the deflated string cache after the last GC and after
  777. * calling js_FinishAtomState, which finalizes strings.
  778. */
  779. js_FinishDeflatedStringCache(rt);
  780. js_FinishGC(rt);
  781. #ifdef JS_THREADSAFE
  782. if (rt->gcLock)
  783. JS_DESTROY_LOCK(rt->gcLock);
  784. if (rt->gcDone)
  785. JS_DESTROY_CONDVAR(rt->gcDone);
  786. if (rt->requestDone)
  787. JS_DESTROY_CONDVAR(rt->requestDone);
  788. if (rt->rtLock)
  789. JS_DESTROY_LOCK(rt->rtLock);
  790. if (rt->stateChange)
  791. JS_DESTROY_CONDVAR(rt->stateChange);
  792. if (rt->titleSharingDone)
  793. JS_DESTROY_CONDVAR(rt->titleSharingDone);
  794. if (rt->debuggerLock)
  795. JS_DESTROY_LOCK(rt->debuggerLock);
  796. #else
  797. GSN_CACHE_CLEAR(&rt->gsnCache);
  798. #endif
  799. js_FinishPropertyTree(rt);
  800. free(rt);
  801. }
  802. JS_PUBLIC_API(void)
  803. JS_ShutDown(void)
  804. {
  805. #ifdef JS_OPMETER
  806. extern void js_DumpOpMeters();
  807. js_DumpOpMeters();
  808. #endif
  809. js_FinishDtoa();
  810. #ifdef JS_THREADSAFE
  811. js_CleanupLocks();
  812. #endif
  813. PRMJ_NowShutdown();
  814. }
  815. JS_PUBLIC_API(void *)
  816. JS_GetRuntimePrivate(JSRuntime *rt)
  817. {
  818. return rt->data;
  819. }
  820. JS_PUBLIC_API(void)
  821. JS_SetRuntimePrivate(JSRuntime *rt, void *data)
  822. {
  823. rt->data = data;
  824. }
  825. JS_PUBLIC_API(void)
  826. JS_BeginRequest(JSContext *cx)
  827. {
  828. #ifdef JS_THREADSAFE
  829. JSRuntime *rt;
  830. JS_ASSERT(cx->thread->id == js_CurrentThreadId());
  831. if (!cx->requestDepth) {
  832. JS_ASSERT(cx->gcLocalFreeLists == &js_GCEmptyFreeListSet);
  833. /* Wait until the GC is finished. */
  834. rt = cx->runtime;
  835. JS_LOCK_GC(rt);
  836. /* NB: we use cx->thread here, not js_GetCurrentThread(). */
  837. if (rt->gcThread != cx->thread) {
  838. while (rt->gcLevel > 0)
  839. JS_AWAIT_GC_DONE(rt);
  840. }
  841. /* Indicate that a request is running. */
  842. rt->requestCount++;
  843. cx->requestDepth = 1;
  844. cx->outstandingRequests++;
  845. JS_UNLOCK_GC(rt);
  846. return;
  847. }
  848. cx->requestDepth++;
  849. cx->outstandingRequests++;
  850. #endif
  851. }
  852. JS_PUBLIC_API(void)
  853. JS_EndRequest(JSContext *cx)
  854. {
  855. #ifdef JS_THREADSAFE
  856. JSRuntime *rt;
  857. JSTitle *title, **todop;
  858. JSBool shared;
  859. CHECK_REQUEST(cx);
  860. JS_ASSERT(cx->requestDepth > 0);
  861. JS_ASSERT(cx->outstandingRequests > 0);
  862. if (cx->requestDepth == 1) {
  863. /* Lock before clearing to interlock with ClaimScope, in jslock.c. */
  864. rt = cx->runtime;
  865. JS_LOCK_GC(rt);
  866. cx->requestDepth = 0;
  867. cx->outstandingRequests--;
  868. /* See whether cx has any single-threaded titles to start sharing. */
  869. todop = &rt->titleSharingTodo;
  870. shared = JS_FALSE;
  871. while ((title = *todop) != NO_TITLE_SHARING_TODO) {
  872. if (title->ownercx != cx) {
  873. todop = &title->u.link;
  874. continue;
  875. }
  876. *todop = title->u.link;
  877. title->u.link = NULL; /* null u.link for sanity ASAP */
  878. /*
  879. * If js_DropObjectMap returns null, we held the last ref to scope.
  880. * The waiting thread(s) must have been killed, after which the GC
  881. * collected the object that held this scope. Unlikely, because it
  882. * requires that the GC ran (e.g., from an operation callback)
  883. * during this request, but possible.
  884. */
  885. if (js_DropObjectMap(cx, TITLE_TO_MAP(title), NULL)) {
  886. js_InitLock(&title->lock);
  887. title->u.count = 0; /* NULL may not pun as 0 */
  888. js_FinishSharingTitle(cx, title); /* set ownercx = NULL */
  889. shared = JS_TRUE;
  890. }
  891. }
  892. if (shared)
  893. JS_NOTIFY_ALL_CONDVAR(rt->titleSharingDone);
  894. js_RevokeGCLocalFreeLists(cx);
  895. /* Give the GC a chance to run if this was the last request running. */
  896. JS_ASSERT(rt->requestCount > 0);
  897. rt->requestCount--;
  898. if (rt->requestCount == 0)
  899. JS_NOTIFY_REQUEST_DONE(rt);
  900. JS_UNLOCK_GC(rt);
  901. return;
  902. }
  903. cx->requestDepth--;
  904. cx->outstandingRequests--;
  905. #endif
  906. }
  907. /* Yield to pending GC operations, regardless of request depth */
  908. JS_PUBLIC_API(void)
  909. JS_YieldRequest(JSContext *cx)
  910. {
  911. #ifdef JS_THREADSAFE
  912. JS_ASSERT(cx->thread);
  913. CHECK_REQUEST(cx);
  914. JS_ResumeRequest(cx, JS_SuspendRequest(cx));
  915. #endif
  916. }
  917. JS_PUBLIC_API(jsrefcount)
  918. JS_SuspendRequest(JSContext *cx)
  919. {
  920. #ifdef JS_THREADSAFE
  921. jsrefcount saveDepth = cx->requestDepth;
  922. while (cx->requestDepth) {
  923. cx->outstandingRequests++; /* compensate for JS_EndRequest */
  924. JS_EndRequest(cx);
  925. }
  926. return saveDepth;
  927. #else
  928. return 0;
  929. #endif
  930. }
  931. JS_PUBLIC_API(void)
  932. JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth)
  933. {
  934. #ifdef JS_THREADSAFE
  935. JS_ASSERT(!cx->requestDepth);
  936. while (--saveDepth >= 0) {
  937. JS_BeginRequest(cx);
  938. cx->outstandingRequests--; /* compensate for JS_BeginRequest */
  939. }
  940. #endif
  941. }
  942. JS_PUBLIC_API(void)
  943. JS_Lock(JSRuntime *rt)
  944. {
  945. JS_LOCK_RUNTIME(rt);
  946. }
  947. JS_PUBLIC_API(void)
  948. JS_Unlock(JSRuntime *rt)
  949. {
  950. JS_UNLOCK_RUNTIME(rt);
  951. }
  952. JS_PUBLIC_API(JSContextCallback)
  953. JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback)
  954. {
  955. JSContextCallback old;
  956. old = rt->cxCallback;
  957. rt->cxCallback = cxCallback;
  958. return old;
  959. }
  960. JS_PUBLIC_API(JSContext *)
  961. JS_NewContext(JSRuntime *rt, size_t stackChunkSize)
  962. {
  963. return js_NewContext(rt, stackChunkSize);
  964. }
  965. JS_PUBLIC_API(void)
  966. JS_DestroyContext(JSContext *cx)
  967. {
  968. js_DestroyContext(cx, JSDCM_FORCE_GC);
  969. }
  970. JS_PUBLIC_API(void)
  971. JS_DestroyContextNoGC(JSContext *cx)
  972. {
  973. js_DestroyContext(cx, JSDCM_NO_GC);
  974. }
  975. JS_PUBLIC_API(void)
  976. JS_DestroyContextMaybeGC(JSContext *cx)
  977. {
  978. js_DestroyContext(cx, JSDCM_MAYBE_GC);
  979. }
  980. JS_PUBLIC_API(void *)
  981. JS_GetContextPrivate(JSContext *cx)
  982. {
  983. return cx->data;
  984. }
  985. JS_PUBLIC_API(void)
  986. JS_SetContextPrivate(JSContext *cx, void *data)
  987. {
  988. cx->data = data;
  989. }
  990. JS_PUBLIC_API(JSRuntime *)
  991. JS_GetRuntime(JSContext *cx)
  992. {
  993. return cx->runtime;
  994. }
  995. JS_PUBLIC_API(JSContext *)
  996. JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
  997. {
  998. return js_ContextIterator(rt, JS_TRUE, iterp);
  999. }
  1000. JS_PUBLIC_API(JSVersion)
  1001. JS_GetVersion(JSContext *cx)
  1002. {
  1003. return JSVERSION_NUMBER(cx);
  1004. }
  1005. JS_PUBLIC_API(JSVersion)
  1006. JS_SetVersion(JSContext *cx, JSVersion version)
  1007. {
  1008. JSVersion oldVersion;
  1009. JS_ASSERT(version != JSVERSION_UNKNOWN);
  1010. JS_ASSERT((version & ~JSVERSION_MASK) == 0);
  1011. oldVersion = JSVERSION_NUMBER(cx);
  1012. if (version == oldVersion)
  1013. return oldVersion;
  1014. /* We no longer support 1.4 or below. */
  1015. if (version != JSVERSION_DEFAULT && version <= JSVERSION_1_4)
  1016. return oldVersion;
  1017. cx->version = (cx->version & ~JSVERSION_MASK) | version;
  1018. js_OnVersionChange(cx);
  1019. return oldVersion;
  1020. }
  1021. static struct v2smap {
  1022. JSVersion version;
  1023. const char *string;
  1024. } v2smap[] = {
  1025. {JSVERSION_1_0, "1.0"},
  1026. {JSVERSION_1_1, "1.1"},
  1027. {JSVERSION_1_2, "1.2"},
  1028. {JSVERSION_1_3, "1.3"},
  1029. {JSVERSION_1_4, "1.4"},
  1030. {JSVERSION_ECMA_3, "ECMAv3"},
  1031. {JSVERSION_1_5, "1.5"},
  1032. {JSVERSION_1_6, "1.6"},
  1033. {JSVERSION_1_7, "1.7"},
  1034. {JSVERSION_1_8, "1.8"},
  1035. {JSVERSION_DEFAULT, js_default_str},
  1036. {JSVERSION_UNKNOWN, NULL}, /* must be last, NULL is sentinel */
  1037. };
  1038. JS_PUBLIC_API(const char *)
  1039. JS_VersionToString(JSVersion version)
  1040. {
  1041. int i;
  1042. for (i = 0; v2smap[i].string; i++)
  1043. if (v2smap[i].version == version)
  1044. return v2smap[i].string;
  1045. return "unknown";
  1046. }
  1047. JS_PUBLIC_API(JSVersion)
  1048. JS_StringToVersion(const char *string)
  1049. {
  1050. int i;
  1051. for (i = 0; v2smap[i].string; i++)
  1052. if (strcmp(v2smap[i].string, string) == 0)
  1053. return v2smap[i].version;
  1054. return JSVERSION_UNKNOWN;
  1055. }
  1056. JS_PUBLIC_API(uint32)
  1057. JS_GetOptions(JSContext *cx)
  1058. {
  1059. return cx->options;
  1060. }
  1061. #define SYNC_OPTIONS_TO_VERSION(cx) \
  1062. JS_BEGIN_MACRO \
  1063. if ((cx)->options & JSOPTION_XML) \
  1064. (cx)->version |= JSVERSION_HAS_XML; \
  1065. else \
  1066. (cx)->version &= ~JSVERSION_HAS_XML; \
  1067. JS_END_MACRO
  1068. JS_PUBLIC_API(uint32)
  1069. JS_SetOptions(JSContext *cx, uint32 options)
  1070. {
  1071. uint32 oldopts = cx->options;
  1072. cx->options = options;
  1073. SYNC_OPTIONS_TO_VERSION(cx);
  1074. return oldopts;
  1075. }
  1076. JS_PUBLIC_API(uint32)
  1077. JS_ToggleOptions(JSContext *cx, uint32 options)
  1078. {
  1079. uint32 oldopts = cx->options;
  1080. cx->options ^= options;
  1081. SYNC_OPTIONS_TO_VERSION(cx);
  1082. return oldopts;
  1083. }
  1084. JS_PUBLIC_API(const char *)
  1085. JS_GetImplementationVersion(void)
  1086. {
  1087. return "JavaScript-C 1.8.0 pre-release 1 2007-10-03";
  1088. }
  1089. JS_PUBLIC_API(JSObject *)
  1090. JS_GetGlobalObject(JSContext *cx)
  1091. {
  1092. return cx->globalObject;
  1093. }
  1094. JS_PUBLIC_API(void)
  1095. JS_SetGlobalObject(JSContext *cx, JSObject *obj)
  1096. {
  1097. cx->globalObject = obj;
  1098. #if JS_HAS_XML_SUPPORT
  1099. cx->xmlSettingFlags = 0;
  1100. #endif
  1101. }
  1102. JS_BEGIN_EXTERN_C
  1103. JSObject *
  1104. js_InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
  1105. {
  1106. JSDHashTable *table;
  1107. JSBool resolving;
  1108. JSRuntime *rt;
  1109. JSResolvingKey key;
  1110. JSResolvingEntry *entry;
  1111. JSObject *fun_proto, *obj_proto;
  1112. /* If cx has no global object, use obj so prototypes can be found. */
  1113. if (!cx->globalObject)
  1114. JS_SetGlobalObject(cx, obj);
  1115. /* Record Function and Object in cx->resolvingTable, if we are resolving. */
  1116. table = cx->resolvingTable;
  1117. resolving = (table && table->entryCount);
  1118. rt = cx->runtime;
  1119. key.obj = obj;
  1120. if (resolving) {
  1121. key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]);
  1122. entry = (JSResolvingEntry *)
  1123. JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
  1124. if (entry && entry->key.obj && (entry->flags & JSRESFLAG_LOOKUP)) {
  1125. /* Already resolving Function, record Object too. */
  1126. JS_ASSERT(entry->key.obj == obj);
  1127. key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
  1128. entry = (JSResolvingEntry *)
  1129. JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
  1130. }
  1131. if (!entry) {
  1132. JS_ReportOutOfMemory(cx);
  1133. return NULL;
  1134. }
  1135. JS_ASSERT(!entry->key.obj && entry->flags == 0);
  1136. entry->key = key;
  1137. entry->flags = JSRESFLAG_LOOKUP;
  1138. } else {
  1139. key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
  1140. if (!js_StartResolving(cx, &key, JSRESFLAG_LOOKUP, &entry))
  1141. return NULL;
  1142. key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]);
  1143. if (!js_StartResolving(cx, &key, JSRESFLAG_LOOKUP, &entry)) {
  1144. key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
  1145. JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
  1146. return NULL;
  1147. }
  1148. table = cx->resolvingTable;
  1149. }
  1150. /* Initialize the function class first so constructors can be made. */
  1151. if (!js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Function),
  1152. &fun_proto)) {
  1153. fun_proto = NULL;
  1154. goto out;
  1155. }
  1156. if (!fun_proto) {
  1157. fun_proto = js_InitFunctionClass(cx, obj);
  1158. if (!fun_proto)
  1159. goto out;
  1160. } else {
  1161. JSObject *ctor;
  1162. ctor = JS_GetConstructor(cx, fun_proto);
  1163. if (!ctor) {
  1164. fun_proto = NULL;
  1165. goto out;
  1166. }
  1167. OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(CLASS_ATOM(cx, Function)),
  1168. OBJECT_TO_JSVAL(ctor), 0, 0, 0, NULL);
  1169. }
  1170. /* Initialize the object class next so Object.prototype works. */
  1171. if (!js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Object),
  1172. &obj_proto)) {
  1173. fun_proto = NULL;
  1174. goto out;
  1175. }
  1176. if (!obj_proto)
  1177. obj_proto = js_InitObjectClass(cx, obj);
  1178. if (!obj_proto) {
  1179. fun_proto = NULL;
  1180. goto out;
  1181. }
  1182. /* Function.prototype and the global object delegate to Object.prototype. */
  1183. OBJ_SET_PROTO(cx, fun_proto, obj_proto);
  1184. if (!OBJ_GET_PROTO(cx, obj))
  1185. OBJ_SET_PROTO(cx, obj, obj_proto);
  1186. out:
  1187. /* If resolving, remove the other entry (Object or Function) from table. */
  1188. JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
  1189. if (!resolving) {
  1190. /* If not resolving, remove the first entry added above, for Object. */
  1191. JS_ASSERT(key.id == \
  1192. ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]));
  1193. key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
  1194. JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
  1195. }
  1196. return fun_proto;
  1197. }
  1198. JS_END_EXTERN_C
  1199. JS_PUBLIC_API(JSBool)
  1200. JS_InitStandardClasses(JSContext *cx, JSObject *obj)
  1201. {
  1202. JSAtom *atom;
  1203. CHECK_REQUEST(cx);
  1204. /* Define a top-level property 'undefined' with the undefined value. */
  1205. atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
  1206. if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
  1207. NULL, NULL, JSPROP_PERMANENT, NULL)) {
  1208. return JS_FALSE;
  1209. }
  1210. /* Function and Object require cooperative bootstrapping magic. */
  1211. if (!js_InitFunctionAndObjectClasses(cx, obj))
  1212. return JS_FALSE;
  1213. /* Initialize the rest of the standard objects and functions. */
  1214. return js_InitArrayClass(cx, obj) &&
  1215. js_InitBlockClass(cx, obj) &&
  1216. js_InitBooleanClass(cx, obj) &&
  1217. js_InitCallClass(cx, obj) &&
  1218. js_InitExceptionClasses(cx, obj) &&
  1219. js_InitMathClass(cx, obj) &&
  1220. js_InitNumberClass(cx, obj) &&
  1221. js_InitJSONClass(cx, obj) &&
  1222. js_InitRegExpClass(cx, obj) &&
  1223. js_InitStringClass(cx, obj) &&
  1224. js_InitEval(cx, obj) &&
  1225. #if JS_HAS_SCRIPT_OBJECT
  1226. js_InitScriptClass(cx, obj) &&
  1227. #endif
  1228. #if JS_HAS_XML_SUPPORT
  1229. js_InitXMLClasses(cx, obj) &&
  1230. #endif
  1231. #if JS_HAS_FILE_OBJECT
  1232. js_InitFileClass(cx, obj) &&
  1233. #endif
  1234. #if JS_HAS_GENERATORS
  1235. js_InitIteratorClasses(cx, obj) &&
  1236. #endif
  1237. js_InitDateClass(cx, obj);
  1238. }
  1239. #define CLASP(name) (&js_##name##Class)
  1240. #define EXT_CLASP(name) (&js_##name##Class.base)
  1241. #define EAGER_ATOM(name) ATOM_OFFSET(name), NULL
  1242. #define EAGER_CLASS_ATOM(name) CLASS_ATOM_OFFSET(name), NULL
  1243. #define EAGER_ATOM_AND_CLASP(name) EAGER_CLASS_ATOM(name), CLASP(name)
  1244. #define EAGER_ATOM_AND_EXT_CLASP(name) EAGER_CLASS_ATOM(name), EXT_CLASP(name)
  1245. #define LAZY_ATOM(name) ATOM_OFFSET(lazy.name), js_##name##_str
  1246. typedef struct JSStdName {
  1247. JSObjectOp init;
  1248. size_t atomOffset; /* offset of atom pointer in JSAtomState */
  1249. const char *name; /* null if atom is pre-pinned, else name */
  1250. JSClass *clasp;
  1251. } JSStdName;
  1252. static JSAtom *
  1253. StdNameToAtom(JSContext *cx, JSStdName *stdn)
  1254. {
  1255. size_t offset;
  1256. JSAtom *atom;
  1257. const char *name;
  1258. offset = stdn->atomOffset;
  1259. atom = OFFSET_TO_ATOM(cx->runtime, offset);
  1260. if (!atom) {
  1261. name = stdn->name;
  1262. if (name) {
  1263. atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED);
  1264. OFFSET_TO_ATOM(cx->runtime, offset) = atom;
  1265. }
  1266. }
  1267. return atom;
  1268. }
  1269. /*
  1270. * Table of class initializers and their atom offsets in rt->atomState.
  1271. * If you add a "standard" class, remember to update this table.
  1272. */
  1273. static JSStdName standard_class_atoms[] = {
  1274. {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Function)},
  1275. {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Object)},
  1276. {js_InitArrayClass, EAGER_ATOM_AND_CLASP(Array)},
  1277. {js_InitBlockClass, EAGER_ATOM_AND_CLASP(Block)},
  1278. {js_InitBooleanClass, EAGER_ATOM_AND_CLASP(Boolean)},
  1279. {js_InitDateClass, EAGER_ATOM_AND_CLASP(Date)},
  1280. {js_InitMathClass, EAGER_ATOM_AND_CLASP(Math)},
  1281. {js_InitNumberClass, EAGER_ATOM_AND_CLASP(Number)},
  1282. {js_InitStringClass, EAGER_ATOM_AND_CLASP(String)},
  1283. {js_InitCallClass, EAGER_ATOM_AND_CLASP(Call)},
  1284. {js_InitExceptionClasses, EAGER_ATOM_AND_CLASP(Error)},
  1285. {js_InitRegExpClass, EAGER_ATOM_AND_CLASP(RegExp)},
  1286. #if JS_HAS_SCRIPT_OBJECT
  1287. {js_InitScriptClass, EAGER_ATOM_AND_CLASP(Script)},
  1288. #endif
  1289. #if JS_HAS_XML_SUPPORT
  1290. {js_InitXMLClass, EAGER_ATOM_AND_CLASP(XML)},
  1291. {js_InitNamespaceClass, EAGER_ATOM_AND_EXT_CLASP(Namespace)},
  1292. {js_InitQNameClass, EAGER_ATOM_AND_EXT_CLASP(QName)},
  1293. #endif
  1294. #if JS_HAS_FILE_OBJECT
  1295. {js_InitFileClass, EAGER_ATOM_AND_CLASP(File)},
  1296. #endif
  1297. #if JS_HAS_GENERATORS
  1298. {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(StopIteration)},
  1299. #endif
  1300. {js_InitJSONClass, EAGER_ATOM_AND_CLASP(JSON)},
  1301. {NULL, 0, NULL, NULL}
  1302. };
  1303. /*
  1304. * Table of top-level function and constant names and their init functions.
  1305. * If you add a "standard" global function or property, remember to update
  1306. * this table.
  1307. */
  1308. static JSStdName standard_class_names[] = {
  1309. /* ECMA requires that eval be a direct property of the global object. */
  1310. {js_InitEval, EAGER_ATOM(eval), NULL},
  1311. /* Global properties and functions defined by the Number class. */
  1312. {js_InitNumberClass, LAZY_ATOM(NaN), NULL},
  1313. {js_InitNumberClass, LAZY_ATOM(Infinity), NULL},
  1314. {js_InitNumberClass, LAZY_ATOM(isNaN), NULL},
  1315. {js_InitNumberClass, LAZY_ATOM(isFinite), NULL},
  1316. {js_InitNumberClass, LAZY_ATOM(parseFloat), NULL},
  1317. {js_InitNumberClass, LAZY_ATOM(parseInt), NULL},
  1318. /* String global functions. */
  1319. {js_InitStringClass, LAZY_ATOM(escape), NULL},
  1320. {js_InitStringClass, LAZY_ATOM(unescape), NULL},
  1321. {js_InitStringClass, LAZY_ATOM(decodeURI), NULL},
  1322. {js_InitStringClass, LAZY_ATOM(encodeURI), NULL},
  1323. {js_InitStringClass, LAZY_ATOM(decodeURIComponent), NULL},
  1324. {js_InitStringClass, LAZY_ATOM(encodeURIComponent), NULL},
  1325. #if JS_HAS_UNEVAL
  1326. {js_InitStringClass, LAZY_ATOM(uneval), NULL},
  1327. #endif
  1328. /* Exception constructors. */
  1329. {js_InitExceptionClasses, EAGER_CLASS_ATOM(Error), CLASP(Error)},
  1330. {js_InitExceptionClasses, EAGER_CLASS_ATOM(InternalError), CLASP(Error)},
  1331. {js_InitExceptionClasses, EAGER_CLASS_ATOM(EvalError), CLASP(Error)},
  1332. {js_InitExceptionClasses, EAGER_CLASS_ATOM(RangeError), CLASP(Error)},
  1333. {js_InitExceptionClasses, EAGER_CLASS_ATOM(ReferenceError), CLASP(Error)},
  1334. {js_InitExceptionClasses, EAGER_CLASS_ATOM(SyntaxError), CLASP(Error)},
  1335. {js_InitExceptionClasses, EAGER_CLASS_ATOM(TypeError), CLASP(Error)},
  1336. {js_InitExceptionClasses, EAGER_CLASS_ATOM(URIError), CLASP(Error)},
  1337. #if JS_HAS_XML_SUPPORT
  1338. {js_InitAnyNameClass, EAGER_ATOM_AND_CLASP(AnyName)},
  1339. {js_InitAttributeNameClass, EAGER_ATOM_AND_CLASP(AttributeName)},
  1340. {js_InitXMLClass, LAZY_ATOM(XMLList), &js_XMLClass},
  1341. {js_InitXMLClass, LAZY_ATOM(isXMLName), NULL},
  1342. #endif
  1343. #if JS_HAS_GENERATORS
  1344. {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Iterator)},
  1345. {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Generator)},
  1346. #endif
  1347. {NULL, 0, NULL, NULL}
  1348. };
  1349. static JSStdName object_prototype_names[] = {
  1350. /* Object.prototype properties (global delegates to Object.prototype). */
  1351. {js_InitObjectClass, EAGER_ATOM(proto), NULL},
  1352. {js_InitObjectClass, EAGER_ATOM(parent), NULL},
  1353. {js_InitObjectClass, EAGER_ATOM(count), NULL},
  1354. #if JS_HAS_TOSOURCE
  1355. {js_InitObjectClass, EAGER_ATOM(toSource), NULL},
  1356. #endif
  1357. {js_InitObjectClass, EAGER_ATOM(toString), NULL},
  1358. {js_InitObjectClass, EAGER_ATOM(toLocaleString), NULL},
  1359. {js_InitObjectClass, EAGER_ATOM(valueOf), NULL},
  1360. #if JS_HAS_OBJ_WATCHPOINT
  1361. {js_InitObjectClass, LAZY_ATOM(watch), NULL},
  1362. {js_InitObjectClass, LAZY_ATOM(unwatch), NULL},
  1363. #endif
  1364. {js_InitObjectClass, LAZY_ATOM(hasOwnProperty), NULL},
  1365. {js_InitObjectClass, LAZY_ATOM(isPrototypeOf), NULL},
  1366. {js_InitObjectClass, LAZY_ATOM(propertyIsEnumerable), NULL},
  1367. #if JS_HAS_GETTER_SETTER
  1368. {js_InitObjectClass, LAZY_ATOM(defineGetter), NULL},
  1369. {js_InitObjectClass, LAZY_ATOM(defineSetter), NULL},
  1370. {js_InitObjectClass, LAZY_ATOM(lookupGetter), NULL},
  1371. {js_InitObjectClass, LAZY_ATOM(lookupSetter), NULL},
  1372. #endif
  1373. {NULL, 0, NULL, NULL}
  1374. };
  1375. JS_PUBLIC_API(JSBool)
  1376. JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id,
  1377. JSBool *resolved)
  1378. {
  1379. JSString *idstr;
  1380. JSRuntime *rt;
  1381. JSAtom *atom;
  1382. JSStdName *stdnm;
  1383. uintN i;
  1384. CHECK_REQUEST(cx);
  1385. *resolved = JS_FALSE;
  1386. rt = cx->runtime;
  1387. JS_ASSERT(rt->state != JSRTS_DOWN);
  1388. if (rt->state == JSRTS_LANDING || !JSVAL_IS_STRING(id))
  1389. return JS_TRUE;
  1390. idstr = JSVAL_TO_STRING(id);
  1391. /* Check whether we're resolving 'undefined', and define it if so. */
  1392. atom = rt->atomState.typeAtoms[JSTYPE_VOID];
  1393. if (idstr == ATOM_TO_STRING(atom)) {
  1394. *resolved = JS_TRUE;
  1395. return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
  1396. NULL, NULL, JSPROP_PERMANENT, NULL);
  1397. }
  1398. /* Try for class constructors/prototypes named by well-known atoms. */
  1399. stdnm = NULL;
  1400. for (i = 0; standard_class_atoms[i].init; i++) {
  1401. atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
  1402. if (idstr == ATOM_TO_STRING(atom)) {
  1403. stdnm = &standard_class_atoms[i];
  1404. break;
  1405. }
  1406. }
  1407. if (!stdnm) {
  1408. /* Try less frequently used top-level functions and constants. */
  1409. for (i = 0; standard_class_names[i].init; i++) {
  1410. atom = StdNameToAtom(cx, &standard_class_names[i]);
  1411. if (!atom)
  1412. return JS_FALSE;
  1413. if (idstr == ATOM_TO_STRING(atom)) {
  1414. stdnm = &standard_class_names[i];
  1415. break;
  1416. }
  1417. }
  1418. if (!stdnm && !OBJ_GET_PROTO(cx, obj)) {
  1419. /*
  1420. * Try even less frequently used names delegated from the global
  1421. * object to Object.prototype, but only if the Object class hasn't
  1422. * yet been initialized.
  1423. */
  1424. for (i = 0; object_prototype_names[i].init; i++) {
  1425. atom = StdNameToAtom(cx, &object_prototype_names[i]);
  1426. if (!atom)
  1427. return JS_FALSE;
  1428. if (idstr == ATOM_TO_STRING(atom)) {
  1429. stdnm = &standard_class_names[i];
  1430. break;
  1431. }
  1432. }
  1433. }
  1434. }
  1435. if (stdnm) {
  1436. /*
  1437. * If this standard class is anonymous and obj advertises itself as a
  1438. * global object (in order to reserve slots for standard class object
  1439. * pointers), then we don't want to resolve by name.
  1440. *
  1441. * If inversely, either id does not name a class, or id does not name
  1442. * an anonymous class, or the global does not reserve slots for class
  1443. * objects, then we must call the init hook here.
  1444. */
  1445. if (stdnm->clasp &&
  1446. (stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS) &&
  1447. (OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_IS_GLOBAL)) {
  1448. return JS_TRUE;
  1449. }
  1450. if (!stdnm->init(cx, obj))
  1451. return JS_FALSE;
  1452. *resolved = JS_TRUE;
  1453. }
  1454. return JS_TRUE;
  1455. }
  1456. static JSBool
  1457. AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, JSAtom *atom)
  1458. {
  1459. JSScopeProperty *sprop;
  1460. JSScope *scope;
  1461. JS_ASSERT(OBJ_IS_NATIVE(obj));
  1462. JS_LOCK_OBJ(cx, obj);
  1463. scope = OBJ_SCOPE(obj);
  1464. sprop = SCOPE_GET_PROPERTY(scope, ATOM_TO_JSID(atom));
  1465. JS_UNLOCK_SCOPE(cx, scope);
  1466. return sprop != NULL;
  1467. }
  1468. JS_PUBLIC_API(JSBool)
  1469. JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
  1470. {
  1471. JSRuntime *rt;
  1472. JSAtom *atom;
  1473. uintN i;
  1474. CHECK_REQUEST(cx);
  1475. rt = cx->runtime;
  1476. /* Check whether we need to bind 'undefined' and define it if so. */
  1477. atom = rt->atomState.typeAtoms[JSTYPE_VOID];
  1478. if (!AlreadyHasOwnProperty(cx, obj, atom) &&
  1479. !OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
  1480. NULL, NULL, JSPROP_PERMANENT, NULL)) {
  1481. return JS_FALSE;
  1482. }
  1483. /* Initialize any classes that have not been resolved yet. */
  1484. for (i = 0; standard_class_atoms[i].init; i++) {
  1485. atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
  1486. if (!AlreadyHasOwnProperty(cx, obj, atom) &&
  1487. !standard_class_atoms[i].init(cx, obj)) {
  1488. return JS_FALSE;
  1489. }
  1490. }
  1491. return JS_TRUE;
  1492. }
  1493. static JSIdArray *
  1494. NewIdArray(JSContext *cx, jsint length)
  1495. {
  1496. JSIdArray *ida;
  1497. ida = (JSIdArray *)
  1498. JS_malloc(cx, offsetof(JSIdArray, vector) + length * sizeof(jsval));
  1499. if (ida)
  1500. ida->length = length;
  1501. return ida;
  1502. }
  1503. /*
  1504. * Unlike realloc(3), this function frees ida on failure.
  1505. */
  1506. static JSIdArray *
  1507. SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length)
  1508. {
  1509. JSIdArray *rida;
  1510. rida = (JSIdArray *)
  1511. JS_realloc(cx, ida,
  1512. offsetof(JSIdArray, vector) + length * sizeof(jsval));
  1513. if (!rida)
  1514. JS_DestroyIdArray(cx, ida);
  1515. else
  1516. rida->length = length;
  1517. return rida;
  1518. }
  1519. static JSIdArray *
  1520. AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip)
  1521. {
  1522. jsint i, length;
  1523. i = *ip;
  1524. length = ida->length;
  1525. if (i >= length) {
  1526. ida = SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
  1527. if (!ida)
  1528. return NULL;
  1529. JS_ASSERT(i < ida->length);
  1530. }
  1531. ida->vector[i] = ATOM_TO_JSID(atom);
  1532. *ip = i + 1;
  1533. return ida;
  1534. }
  1535. static JSIdArray *
  1536. EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida,
  1537. jsint *ip, JSBool *foundp)
  1538. {
  1539. *foundp = AlreadyHasOwnProperty(cx, obj, atom);
  1540. if (*foundp)
  1541. ida = AddAtomToArray(cx, atom, ida, ip);
  1542. return ida;
  1543. }
  1544. JS_PUBLIC_API(JSIdArray *)
  1545. JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj,
  1546. JSIdArray *ida)
  1547. {
  1548. JSRuntime *rt;
  1549. jsint i, j, k;
  1550. JSAtom *atom;
  1551. JSBool found;
  1552. JSObjectOp init;
  1553. CHECK_REQUEST(cx);
  1554. rt = cx->runtime;
  1555. if (ida) {
  1556. i = ida->length;
  1557. } else {
  1558. ida = NewIdArray(cx, 8);
  1559. if (!ida)
  1560. return NULL;
  1561. i = 0;
  1562. }
  1563. /* Check whether 'undefined' has been resolved and enumerate it if so. */
  1564. atom = rt->atomState.typeAtoms[JSTYPE_VOID];
  1565. ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
  1566. if (!ida)
  1567. return NULL;
  1568. /* Enumerate only classes that *have* been resolved. */
  1569. for (j = 0; standard_class_atoms[j].init; j++) {
  1570. atom = OFFSET_TO_ATOM(rt, standard_class_atoms[j].atomOffset);
  1571. ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
  1572. if (!ida)
  1573. return NULL;
  1574. if (found) {
  1575. init = standard_class_atoms[j].init;
  1576. for (k = 0; standard_class_names[k].init; k++) {
  1577. if (standard_class_names[k].init == init) {
  1578. atom = StdNameToAtom(cx, &standard_class_names[k]);
  1579. ida = AddAtomToArray(cx, atom, ida, &i);
  1580. if (!ida)
  1581. return NULL;
  1582. }
  1583. }
  1584. if (init == js_InitObjectClass) {
  1585. for (k = 0; object_prototype_names[k].init; k++) {
  1586. atom = StdNameToAtom(cx, &object_prototype_names[k]);
  1587. ida = AddAtomToArray(cx, atom, ida, &i);
  1588. if (!ida)
  1589. return NULL;
  1590. }
  1591. }
  1592. }
  1593. }
  1594. /* Trim to exact length. */
  1595. return SetIdArrayLength(cx, ida, i);
  1596. }
  1597. #undef CLASP
  1598. #undef EAGER_ATOM
  1599. #undef EAGER_CLASS_ATOM
  1600. #undef EAGER_ATOM_CLASP
  1601. #undef LAZY_ATOM
  1602. JS_PUBLIC_API(JSBool)
  1603. JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key,
  1604. JSObject **objp)
  1605. {
  1606. CHECK_REQUEST(cx);
  1607. return js_GetClassObject(cx, obj, key, objp);
  1608. }
  1609. JS_PUBLIC_API(JSObject *)
  1610. JS_GetScopeChain(JSContext *cx)
  1611. {
  1612. JSStackFrame *fp;
  1613. CHECK_REQUEST(cx);
  1614. fp = cx->fp;
  1615. if (!fp) {
  1616. /*
  1617. * There is no code active on this context. In place of an actual
  1618. * scope chain, use the context's global object, which is set in
  1619. * js_InitFunctionAndObjectClasses, and which represents the default
  1620. * scope chain for the embedding. See also js_FindClassObject.
  1621. *
  1622. * For embeddings that use the inner and outer object hooks, the inner
  1623. * object represents the ultimate global object, with the outer object
  1624. * acting as a stand-in.
  1625. */
  1626. JSObject *obj = cx->globalObject;
  1627. if (!obj) {
  1628. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE);
  1629. return NULL;
  1630. }
  1631. OBJ_TO_INNER_OBJECT(cx, obj);
  1632. return obj;
  1633. }
  1634. return js_GetScopeChain(cx, fp);
  1635. }
  1636. JS_PUBLIC_API(JSObject *)
  1637. JS_GetGlobalForObject(JSContext *cx, JSObject *obj)
  1638. {
  1639. JSObject *parent;
  1640. while ((parent = OBJ_GET_PARENT(cx, obj)) != NULL)
  1641. obj = parent;
  1642. return obj;
  1643. }
  1644. JS_PUBLIC_API(jsval)
  1645. JS_ComputeThis(JSContext *cx, jsval *vp)
  1646. {
  1647. if (!js_ComputeThis(cx, JS_FALSE, vp + 2))
  1648. return JSVAL_NULL;
  1649. return vp[1];
  1650. }
  1651. JS_PUBLIC_API(void *)
  1652. JS_malloc(JSContext *cx, size_t nbytes)
  1653. {
  1654. void *p;
  1655. JS_ASSERT(nbytes != 0);
  1656. JS_COUNT_OPERATION(cx, JSOW_ALLOCATION);
  1657. if (nbytes == 0)
  1658. nbytes = 1;
  1659. p = malloc(nbytes);
  1660. if (!p) {
  1661. JS_ReportOutOfMemory(cx);
  1662. return NULL;
  1663. }
  1664. js_UpdateMallocCounter(cx, nbytes);
  1665. return p;
  1666. }
  1667. JS_PUBLIC_API(void *)
  1668. JS_realloc(JSContext *cx, void *p, size_t nbytes)
  1669. {
  1670. JS_COUNT_OPERATION(cx, JSOW_ALLOCATION);
  1671. p = realloc(p, nbytes);
  1672. if (!p)
  1673. JS_ReportOutOfMemory(cx);
  1674. return p;
  1675. }
  1676. JS_PUBLIC_API(void)
  1677. JS_free(JSContext *cx, void *p)
  1678. {
  1679. if (p)
  1680. free(p);
  1681. }
  1682. JS_PUBLIC_API(char *)
  1683. JS_strdup(JSContext *cx, const char *s)
  1684. {
  1685. size_t n;
  1686. void *p;
  1687. n = strlen(s) + 1;
  1688. p = JS_malloc(cx, n);
  1689. if (!p)
  1690. return NULL;
  1691. return (char *)memcpy(p, s, n);
  1692. }
  1693. JS_PUBLIC_API(jsdouble *)
  1694. JS_NewDouble(JSContext *cx, jsdouble d)
  1695. {
  1696. CHECK_REQUEST(cx);
  1697. return js_NewWeaklyRootedDouble(cx, d);
  1698. }
  1699. JS_PUBLIC_API(JSBool)
  1700. JS_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval)
  1701. {
  1702. jsdouble *dp;
  1703. CHECK_REQUEST(cx);
  1704. dp = js_NewWeaklyRootedDouble(cx, d);
  1705. if (!dp)
  1706. return JS_FALSE;
  1707. *rval = DOUBLE_TO_JSVAL(dp);
  1708. return JS_TRUE;
  1709. }
  1710. JS_PUBLIC_API(JSBool)
  1711. JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
  1712. {
  1713. jsint i;
  1714. CHECK_REQUEST(cx);
  1715. if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) {
  1716. *rval = INT_TO_JSVAL(i);
  1717. return JS_TRUE;
  1718. }
  1719. return JS_NewDoubleValue(cx, d, rval);
  1720. }
  1721. #undef JS_AddRoot
  1722. JS_PUBLIC_API(JSBool)
  1723. JS_AddRoot(JSContext *cx, void *rp)
  1724. {
  1725. CHECK_REQUEST(cx);
  1726. return js_AddRoot(cx, rp, NULL);
  1727. }
  1728. JS_PUBLIC_API(JSBool)
  1729. JS_AddNamedRootRT(JSRuntime *rt, void *rp, const char *name)
  1730. {
  1731. return js_AddRootRT(rt, rp, name);
  1732. }
  1733. JS_PUBLIC_API(JSBool)
  1734. JS_RemoveRoot(JSContext *cx, void *rp)
  1735. {
  1736. CHECK_REQUEST(cx);
  1737. return js_RemoveRoot(cx->runtime, rp);
  1738. }
  1739. JS_PUBLIC_API(JSBool)
  1740. JS_RemoveRootRT(JSRuntime *rt, void *rp)
  1741. {
  1742. return js_RemoveRoot(rt, rp);
  1743. }
  1744. JS_PUBLIC_API(JSBool)
  1745. JS_AddNamedRoot(JSContext *cx, void *rp, const char *name)
  1746. {
  1747. CHECK_REQUEST(cx);
  1748. return js_AddRoot(cx, rp, name);
  1749. }
  1750. JS_PUBLIC_API(void)
  1751. JS_ClearNewbornRoots(JSContext *cx)
  1752. {
  1753. JS_CLEAR_WEAK_ROOTS(&cx->weakRoots);
  1754. }
  1755. JS_PUBLIC_API(JSBool)
  1756. JS_EnterLocalRootScope(JSContext *cx)
  1757. {
  1758. CHECK_REQUEST(cx);
  1759. return js_EnterLocalRootScope(cx);
  1760. }
  1761. JS_PUBLIC_API(void)
  1762. JS_LeaveLocalRootScope(JSContext *cx)
  1763. {
  1764. CHECK_REQUEST(cx);
  1765. js_LeaveLocalRootScope(cx);
  1766. }
  1767. JS_PUBLIC_API(void)
  1768. JS_LeaveLocalRootScopeWithResult(JSContext *cx, jsval rval)
  1769. {
  1770. CHECK_REQUEST(cx);
  1771. js_LeaveLocalRootScopeWithResult(cx, rval);
  1772. }
  1773. JS_PUBLIC_API(void)
  1774. JS_ForgetLocalRoot(JSContext *cx, void *thing)
  1775. {
  1776. CHECK_REQUEST(cx);
  1777. js_ForgetLocalRoot(cx, (jsval) thing);
  1778. }
  1779. #ifdef DEBUG
  1780. JS_PUBLIC_API(void)
  1781. JS_DumpNamedRoots(JSRuntime *rt,
  1782. void (*dump)(const char *name, void *rp, void *data),
  1783. void *data)
  1784. {
  1785. js_DumpNamedRoots(rt, dump, data);
  1786. }
  1787. #endif /* DEBUG */
  1788. JS_PUBLIC_API(uint32)
  1789. JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
  1790. {
  1791. return js_MapGCRoots(rt, map, data);
  1792. }
  1793. JS_PUBLIC_API(JSBool)
  1794. JS_LockGCThing(JSContext *cx, void *thing)
  1795. {
  1796. JSBool ok;
  1797. CHECK_REQUEST(cx);
  1798. ok = js_LockGCThingRT(cx->runtime, thing);
  1799. if (!ok)
  1800. JS_ReportOutOfMemory(cx);
  1801. return ok;
  1802. }
  1803. JS_PUBLIC_API(JSBool)
  1804. JS_LockGCThingRT(JSRuntime *rt, void *thing)
  1805. {
  1806. return js_LockGCThingRT(rt, thing);
  1807. }
  1808. JS_PUBLIC_API(JSBool)
  1809. JS_UnlockGCThing(JSContext *cx, void *thing)
  1810. {
  1811. JSBool ok;
  1812. CHECK_REQUEST(cx);
  1813. ok = js_UnlockGCThingRT(cx->runtime, thing);
  1814. if (!ok)
  1815. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_UNLOCK);
  1816. return ok;
  1817. }
  1818. JS_PUBLIC_API(JSBool)
  1819. JS_UnlockGCThingRT(JSRuntime *rt, void *thing)
  1820. {
  1821. return js_UnlockGCThingRT(rt, thing);
  1822. }
  1823. JS_PUBLIC_API(void)
  1824. JS_SetExtraGCRoots(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
  1825. {
  1826. rt->gcExtraRootsTraceOp = traceOp;
  1827. rt->gcExtraRootsData = data;
  1828. }
  1829. JS_PUBLIC_API(void)
  1830. JS_TraceRuntime(JSTracer *trc)
  1831. {
  1832. JSBool allAtoms = trc->context->runtime->gcKeepAtoms != 0;
  1833. js_TraceRuntime(trc, allAtoms);
  1834. }
  1835. #ifdef DEBUG
  1836. #ifdef HAVE_XPCONNECT
  1837. #include "dump_xpc.h"
  1838. #endif
  1839. JS_PUBLIC_API(void)
  1840. JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc,
  1841. void *thing, uint32 kind, JSBool details)
  1842. {
  1843. const char *name;
  1844. size_t n;
  1845. if (bufsize == 0)
  1846. return;
  1847. switch (kind) {
  1848. case JSTRACE_OBJECT:
  1849. {
  1850. JSObject *obj = (JSObject *)thing;
  1851. JSClass *clasp = STOBJ_GET_CLASS(obj);
  1852. name = clasp->name;
  1853. #ifdef HAVE_XPCONNECT
  1854. if (clasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) {
  1855. jsval privateValue = STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE);
  1856. JS_ASSERT(clasp->flags & JSCLASS_HAS_PRIVATE);
  1857. if (!JSVAL_IS_VOID(privateValue)) {
  1858. void *privateThing = JSVAL_TO_PRIVATE(privateValue);
  1859. const char *xpcClassName = GetXPCObjectClassName(privateThing);
  1860. if (xpcClassName)
  1861. name = xpcClassName;
  1862. }
  1863. }
  1864. #endif
  1865. break;
  1866. }
  1867. case JSTRACE_STRING:
  1868. name = JSSTRING_IS_DEPENDENT((JSString *)thing)
  1869. ? "substring"
  1870. : "string";
  1871. break;
  1872. case JSTRACE_DOUBLE:
  1873. name = "double";
  1874. break;
  1875. #if JS_HAS_XML_SUPPORT
  1876. case JSTRACE_XML:
  1877. name = "xml";
  1878. break;
  1879. #endif
  1880. default:
  1881. JS_ASSERT(0);
  1882. return;
  1883. break;
  1884. }
  1885. n = strlen(name);
  1886. if (n > bufsize - 1)
  1887. n = bufsize - 1;
  1888. memcpy(buf, name, n + 1);
  1889. buf += n;
  1890. bufsize -= n;
  1891. if (details && bufsize > 2) {
  1892. *buf++ = ' ';
  1893. bufsize--;
  1894. switch (kind) {
  1895. case JSTRACE_OBJECT:
  1896. {
  1897. JSObject *obj = (JSObject *)thing;
  1898. JSClass *clasp = STOBJ_GET_CLASS(obj);
  1899. if (clasp == &js_FunctionClass) {
  1900. JSFunction *fun = (JSFunction *)
  1901. JS_GetPrivate(trc->context, obj);
  1902. if (!fun) {
  1903. JS_snprintf(buf, bufsize, "<newborn>");
  1904. } else if (FUN_OBJECT(fun) != obj) {
  1905. JS_snprintf(buf, bufsize, "%p", fun);
  1906. } else {
  1907. if (fun->atom && ATOM_IS_STRING(fun->atom))
  1908. js_PutEscapedString(buf, bufsize,
  1909. ATOM_TO_STRING(fun->atom), 0);
  1910. }
  1911. } else if (clasp->flags & JSCLASS_HAS_PRIVATE) {
  1912. jsval privateValue = STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE);
  1913. void *privateThing = JSVAL_IS_VOID(privateValue)
  1914. ? NULL
  1915. : JSVAL_TO_PRIVATE(privateValue);
  1916. JS_snprintf(buf, bufsize, "%p", privateThing);
  1917. } else {
  1918. JS_snprintf(buf, bufsize, "<no private>");
  1919. }
  1920. break;
  1921. }
  1922. case JSTRACE_STRING:
  1923. js_PutEscapedString(buf, bufsize, (JSString *)thing, 0);
  1924. break;
  1925. case JSTRACE_DOUBLE:
  1926. JS_snprintf(buf, bufsize, "%g", *(jsdouble *)thing);
  1927. break;
  1928. #if JS_HAS_XML_SUPPORT
  1929. case JSTRACE_XML:
  1930. {
  1931. extern const char *js_xml_class_str[];
  1932. JSXML *xml = (JSXML *)thing;
  1933. JS_snprintf(buf, bufsize, "%s", js_xml_class_str[xml->xml_class]);
  1934. break;
  1935. }
  1936. #endif
  1937. default:
  1938. JS_ASSERT(0);
  1939. break;
  1940. }
  1941. }
  1942. buf[bufsize - 1] = '\0';
  1943. }
  1944. typedef struct JSHeapDumpNode JSHeapDumpNode;
  1945. struct JSHeapDumpNode {
  1946. void *thing;
  1947. uint32 kind;
  1948. JSHeapDumpNode *next; /* next sibling */
  1949. JSHeapDumpNode *parent; /* node with the thing that refer to thing
  1950. from this node */
  1951. char edgeName[1]; /* name of the edge from parent->thing
  1952. into thing */
  1953. };
  1954. typedef struct JSDumpingTracer {
  1955. JSTracer base;
  1956. JSDHashTable visited;
  1957. JSBool ok;
  1958. void *startThing;
  1959. void *thingToFind;
  1960. void *thingToIgnore;
  1961. JSHeapDumpNode *parentNode;
  1962. JSHeapDumpNode **lastNodep;
  1963. char buffer[200];
  1964. } JSDumpingTracer;
  1965. static void
  1966. DumpNotify(JSTracer *trc, void *thing, uint32 kind)
  1967. {
  1968. JSDumpingTracer *dtrc;
  1969. JSContext *cx;
  1970. JSDHashEntryStub *entry;
  1971. JSHeapDumpNode *node;
  1972. const char *edgeName;
  1973. size_t edgeNameSize;
  1974. JS_ASSERT(trc->callback == DumpNotify);
  1975. dtrc = (JSDumpingTracer *)trc;
  1976. if (!dtrc->ok || thing == dtrc->thingToIgnore)
  1977. return;
  1978. cx = trc->context;
  1979. /*
  1980. * Check if we have already seen thing unless it is thingToFind to include
  1981. * it to the graph each time we reach it and print all live things that
  1982. * refer to thingToFind.
  1983. *
  1984. * This does not print all possible paths leading to thingToFind since
  1985. * when a thing A refers directly or indirectly to thingToFind and A is
  1986. * present several times in the graph, we will print only the first path
  1987. * leading to A and thingToFind, other ways to reach A will be ignored.
  1988. */
  1989. if (dtrc->thingToFind != thing) {
  1990. /*
  1991. * The startThing check allows to avoid putting startThing into the
  1992. * hash table before tracing startThing in JS_DumpHeap.
  1993. */
  1994. if (thing == dtrc->startThing)
  1995. return;
  1996. entry = (JSDHashEntryStub *)
  1997. JS_DHashTableOperate(&dtrc->visited, thing, JS_DHASH_ADD);
  1998. if (!entry) {
  1999. JS_ReportOutOfMemory(cx);
  2000. dtrc->ok = JS_FALSE;
  2001. return;
  2002. }
  2003. if (entry->key)
  2004. return;
  2005. entry->key = thing;
  2006. }
  2007. if (dtrc->base.debugPrinter) {
  2008. dtrc->base.debugPrinter(trc, dtrc->buffer, sizeof(dtrc->buffer));
  2009. edgeName = dtrc->buffer;
  2010. } else if (dtrc->base.debugPrintIndex != (size_t)-1) {
  2011. JS_snprintf(dtrc->buffer, sizeof(dtrc->buffer), "%s[%lu]",
  2012. (const char *)dtrc->base.debugPrintArg,
  2013. dtrc->base.debugPrintIndex);
  2014. edgeName = dtrc->buffer;
  2015. } else {
  2016. edgeName = (const char*)dtrc->base.debugPrintArg;
  2017. }
  2018. edgeNameSize = strlen(edgeName) + 1;
  2019. node = (JSHeapDumpNode *)
  2020. JS_malloc(cx, offsetof(JSHeapDumpNode, edgeName) + edgeNameSize);
  2021. if (!node) {
  2022. dtrc->ok = JS_FALSE;
  2023. return;
  2024. }
  2025. node->thing = thing;
  2026. node->kind = kind;
  2027. node->next = NULL;
  2028. node->parent = dtrc->parentNode;
  2029. memcpy(node->edgeName, edgeName, edgeNameSize);
  2030. JS_ASSERT(!*dtrc->lastNodep);
  2031. *dtrc->lastNodep = node;
  2032. dtrc->lastNodep = &node->next;
  2033. }
  2034. /* Dump node and the chain that leads to thing it contains. */
  2035. static JSBool
  2036. DumpNode(JSDumpingTracer *dtrc, FILE* fp, JSHeapDumpNode *node)
  2037. {
  2038. JSHeapDumpNode *prev, *following;
  2039. size_t chainLimit;
  2040. JSBool ok;
  2041. enum { MAX_PARENTS_TO_PRINT = 10 };
  2042. JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
  2043. &dtrc->base, node->thing, node->kind, JS_TRUE);
  2044. if (fprintf(fp, "%p %-22s via ", node->thing, dtrc->buffer) < 0)
  2045. return JS_FALSE;
  2046. /*
  2047. * We need to print the parent chain in the reverse order. To do it in
  2048. * O(N) time where N is the chain length we first reverse the cha